Odborný článok

Priradené súbory na úrovni stránky v PDF 2.0 s PDFlibPas

PDFlibPas pripevní vložený súbor na jednu konkrétnu stránku namiesto na dokument ako celok tak, že zapíše pole /AF do slovníka strany, kým samotný payload zostáva zaregistrovaný v strome názvov EmbeddedFiles dokumentu. Toto rozdelenie popisuje ISO 32000-2 §14.13 a práve ono umožňuje čítačke odpovedať na otázku, ktorú príloha na úrovni dokumentu zodpovedať nedokáže: ku ktorej stránke tieto dáta patria

Použitia sú špecifickejšie než pri všeobecných prílohách. Správa z prieskumu, kde každá strana nesie surovú rad meraní, z ktorej vznikol jej graf. Naskenovaná dávka, kde si každá strana uchováva OCR výsledok, ktorý vyrobil jej textovú vrstvu. Súprava výkresov, kde každý list nesie CAD výpis, z ktorého bol vykreslený. V každom prípade by bol zoznam príloh na úrovni dokumentu hromadou súborov s názvami kódujúcimi čísla strán, čo je konvencia, nie štruktúra

Jeden payload, dve miesta, kde sa naň odkazuje

Dôležitý štrukturálny bod znie, že priradenie na úrovni strany nevytvára druhú kópiu čohokoľvek. Súbor je vložený raz a zaregistrovaný v strome názvov EmbeddedFiles úplne rovnako ako príloha na úrovni dokumentu, s použitím toho istého mechanizmu file specification. Líši sa iba miesto, kam sa zapisuje referencia a jej kľúč vzťahu: do slovníka strany namiesto katalógu dokumentu

Z toho vyplývajú dva dôsledky. Po prvé, čítačka, ktorá pozná len prílohy na úrovni dokumentu, payload aj tak nájde, pretože je v strome názvov, kam takáto čítačka pozerá. Po druhé, zrušenie priradenia strany odstráni väzbu, nie súbor. ClearPageAssociatedFiles odpojí stranu od jej priradených súborov a nechá payloady dostupné cez strom názvov, čo je konzervatívne správanie: operácia, ktorá hovorí zruš priradenie, nemá potichu zničiť dáta, na ktoré sa môže odkazovať iná časť dokumentu

Štruktúra súboru priradeného na úrovni strany v dokumente PDF 2.0 zapísanom PDFlibPas: payload je vložený raz a zaregistrovaný v strome názvov EmbeddedFiles pod katalógom dokumentu, kým slovník strany nesie pole /AF odkazujúce na rovnakú file specification s kľúčom AFRelationship, takže ClearPageAssociatedFiles odpojí väzbu bez zničenia dát
Priradenie na úrovni strany pridáva druhú referenciu, nie druhú kópiu: čítačky poznajúce len prílohy na úrovni dokumentu nájdu payload v strome názvov aj naďalej a zrušenie väzby strany nechá vložený stream dostupný

Tá funkcia má jednu zámernú úzku podmienku úspechu, ktorá stojí za poznanie. Úspech hlási iba vtedy, keď strana skutočne niesla kľúč /AF. Strana, ktorá nikdy žiadne priradenia nemala, vráti zlyhanie namiesto povzbudného potvrdenia, takže volajúci si nemôže no-op pomýliť s dokončeným upratovaním

var
  Lib: TPDFlib;
  Idx, I: Integer;
begin
  Lib := TPDFlib.Create(nil);
  try
    Lib.LoadFromFile('survey-report.pdf');

    // Pripoj rad meraní, z ktorého vznikol graf na strane 3
    Idx := Lib.AddPageAssociatedFileFromFile(3,
      'series-03.csv',            // súbor na disku
      'measurements.csv',         // zobrazovaný názov vnútri PDF
      'text/csv',                 // MIME typ
      'Raw measurement series for figure 3',
      'Data');                    // AFRelationship, ISO 32000-2 14.13

    if Idx < 0 then
      raise Exception.Create('page association refused');

    for I := 0 to Lib.GetPageAssociatedFileCount(3) - 1 do
      Writeln('page 3 associated file, embedded index ',
        Lib.GetPageAssociatedFileEmbeddedIndex(3, I));

    Lib.SaveToFile('survey-report-with-data.pdf');
  finally
    Lib.Free;
  end;
end;

Reťazec vzťahu nie je v praxi voľný text. ISO 32000-2 definuje slovník hodnôt: Source, Data, Alternative, Supplement, EncryptedPayload, FormData, Schema a Unspecified, a konzumenti sa podľa neho riadia. Data pre čísla za grafom, Source pre dokument, z ktorého bola strana vygenerovaná, Alternative pre ekvivalentnú reprezentáciu. Vybierajte zo slovníka aj vtedy, keď ešte nič vo vašom pipeline nečíta túto hodnotu, pretože ďalší nástroj v reťazci čítať môže

Prečo potrebuje rovnaké vyhľadávanie FollowRef v oboch smeroch?

Pretože nasledovanie referencií odpovedá na dve odlišné otázky a kód musí vedieť, ktorú z nich kladie. Vyhľadávanie kľúča, ktoré nasleduje nepriame referencie, vráti objekt, na ktorý referencia ukazuje. Vyhľadávanie, ktoré nenasleduje, vráti samotnú referenciu. Obe sú správne a použitie nesprávnej vyprodukuje tiché nesprávne správanie namiesto chyby

Čítanie priradeného súboru demonštruje prvý smer. Ak chcete získať číslo objektu vloženého streamu za kľúčmi file specification /EF a /F, vyhľadávanie nesmie nasledovať, pretože nasledovanie zreferencuje referenciu do stream objektu a číslo objektu je preč. Pravidlo sa zovšeobecňuje: akákoľvek kódová cesta, ktorá potrebuje identitu objektu namiesto obsahu objektu, musí vziať surovú referenciu

Optional content ukazuje opačný smer a stálo ho viac námahy nájsť. Slovník vlastností optional content sa zapisuje do katalógu ako nepriamy objekt, takže kód, ktorý ho číta späť bez nasledovania, dostane referenciu namiesto slovníka. Kontrola typu na tejto hodnote potom zlyhá a prirodzená fallback vetva, ak neexistuje konfigurácia, vytvor ju, sa spustí a prepíše konfiguráciu, ktorá tam už bola. Nič nezvýši výnimku. Vrstvy popísané v článku skupiny optional content a vrstvy jednoducho stratia svoj predvolený stav viditeľnosti

Ponaučenie sa zobecňuje za obe prípady. Keď môže vyhľadávanie vrátiť referenciu alebo objekt, holá kontrola typu nie je spracovanie chýb: je to vetva, ktorá sa raz zaberie zo zlého dôvodu. Rozhodnite sa explicitne, čo každé miesto volania potrebuje, a uprednostnite verejné API, ktoré odpovedá na otázku priamo, napríklad vlastnosť počtu optional content, pred zanorovaním sa do chráneného prístupového prvku ku katalógovému slovníku

Mapa rozhodnutí pre nasledovanie referencií pri PDF vyhľadávaniach implementovanom v PDFlibPas: čítanie /EF a /F pod file specification nesmie referenciu nasledovať, pretože odpoveďou je číslo objektu vloženého streamu, kým nepriamy slovník /OCProperties v katalógu nasledovaný byť musí, inak neúspešná kontrola typu poticho prepíše existujúcu konfiguráciu optional content
Rovnaké vyhľadávanie odpovedá na dve odlišné otázky: identita potrebuje surovú referenciu, obsah potrebuje zreferencovaný objekt a holá kontrola typu namiesto tohto rozhodnutia raz spustí nesprávnu vetvu bez zvýšenia výnimky
// Prílohy na úrovni dokumentu a priradenia na úrovni strany koexistujú.
// Vložený súbor sa dá označiť ako priradený aj na úrovni dokumentu
if Lib.IsEmbeddedFileAssociated(0) = 0 then
  Lib.SetEmbeddedFileAssociated(0, 1, 'Supplement');

Writeln('document associated files: ', Lib.GetAssociatedFileCount);
Writeln('page 3 associated files  : ',
        Lib.GetPageAssociatedFileCount(3));

// Zrušenie odpojí väzbu strany; payload zostáva v strome názvov
if Lib.ClearPageAssociatedFiles(3) > 0 then
  Writeln('page 3 associations removed, payloads still reachable');

Čo robia režimy zhody s prílohami

Archívne profily obmedzujú, čo sa smie vložiť, a to obmedzenie sa vynucuje na vstupnom bode, nie až pri ukladaní. PDF/A-1 zakazuje vložené súbory úplne, PDF/A-2 povoľuje iba vložené dokumenty PDF/A a PDF/A-3 je profil, ktorý otvoril vkladanie ľubovoľným typom súborov, a presne preto na ňom stoja hybridné formáty faktúr

PDFlibPas odmietne prílohu, keď jej aktívny režim zhody nedovoľuje, a to hneď pri volaní, nie stovky operácií neskôr počas výstupu. To je zámerná voľba miesta, kde je chyba najlacnejšie riešiť: odmietnutie na mieste volania menuje súbor, ktorý ste pridávali, zatiaľ čo odmietnutie pri ukladaní menuje dokument a nechá vás rozlúštiť, ktorá zo štyridsať príloh to spôsobila

Práve preto sa priradené súbory objavujú tak často v elektronickej fakturácii. Hybridná faktúra je PDF, ktoré človek číta, s pripojeným strojovo čitateľným XML payloadom označeným správnym vzťahom, a profil kontajnera aj kľúč vzťahu sú súčasťou špecifikácie, nie konvencií. Táto konštrukcia je rozobraná v článku tvorba hybridných faktúr Factur-X a ZUGFeRD, strana metadát v článku XMP extension schema pre PDF/A-3

Kedy má byť priradenie na stranu, nie na dokument?

Vtedy, keď konzument potrebuje vedieť, ku ktorej strane dáta patria, a len vtedy. Prílohy na úrovni dokumentu sú jednoduchšie, širšie podporované prehliadačmi a postačujú vždy, keď payload opisuje celý dokument, XML faktúry, manifest podpisu, archív zdrojov. Po priradení na úrovni strany siahnite, keď je payload naozaj viazaný na stranu a identita strany je súčasťou jeho významu

Podpora je praktické obmedzenie. Súbory priradené na úrovni strany sú konštrukt PDF 2.0 a podpora v prehliadačoch je tenšia než pri prílohách na úrovni dokumentu. Keďže payload sedí v strome názvov v oboch prípadoch, prehliadač, ktorý ignoruje /AF na stranách, stále ukáže súbor v zozname príloh, takže degradácia je ústretová. Ale ak je väzba na stranu pre váš konzument nevyhnutná, nie len užitočná metadáta, overte si čítačku, ktorú skutočne cieľujete, namiesto domnienok

Súbory priradené na úrovni strany, prílohy na úrovni dokumentu aj archívne profily riadiace oboje prichádzajú v PDFlibPas Delphi PDF knižnici. Ak cestou opravujete aj staršie súbory, práca s metadátami a zhodou v článku konverzia na PDF/A s opravou metadát je to, čo rozhodne, ktorá z týchto ciest príloh je vám vôbec dostupná