Tehnički članak

Datoteke povezane na nivou strane u PDF 2.0 uz PDFlibPas

PDFlibPas kači ugrađenu datoteku na jednu konkretnu stranu, a ne na dokument kao celinu, tako što upisuje /AF niz u rečnik stranice dok sam payload ostaje evidentiran u EmbeddedFiles name stablu dokumenta. Ta podela je ono što ISO 32000-2 §14.13 opisuje, i upravo ona čitaču daje odgovor na pitanje koje prilog na nivou dokumenta ne može da da: kojoj strani ovi podaci pripadaju

Slučajevi upotrebe su konkretniji od opštih priloga. Izveštaj o premeru gde svaka strana nosi sirove serije merenja iza svog grafikona. Skeniran paket gde svaka strana čuva OCR rezultat koji je proizveo njen tekstualni sloj. Zbirka crteža gde svaki list nosi CAD izvod iz kojeg je renderovan. U svakom od tih slučajeva spisak priloga na nivou dokumenta bio bi gomila datoteka čija imena u sebi nose brojeve strana, a to je konvencija, ne struktura

Jedan payload, dva mesta sa kojih se na njega referencira

Ključna strukturna tačka je da povezanost na nivou strane ne pravi drugi primerak ičega. Datoteka se ugrađuje jednom i evidentira u EmbeddedFiles name stablu potpuno isto kao prilog na nivou dokumenta, koristeći isti mehanizam file specification-a. Razlika je u tome gde se upisuju referenca i njen ključ odnosa: u rečnik stranice umesto u katalog dokumenta

Iz toga slede dve posledice. Prvo, čitač koji zna samo za priloge na nivou dokumenta i dalje nalazi payload, jer se on nalazi u name stablu gde takav čitač traži. Drugo, brisanje povezanosti stranice uklanja vezu, a ne datoteku. ClearPageAssociatedFiles otkačuje stranu od njenih povezanih datoteka i ostavlja payload-e dostižnim kroz name stablo, a to je konzervativno ponašanje: operacija koja kaže obriši povezanost ne sme tiho da uništi podatke na koje drugi deo dokumenta možda referencira

Struktura datoteke povezane na nivou strane u PDF 2.0 dokumentu koji piše PDFlibPas: payload je ugrađen jednom i evidentiran u EmbeddedFiles name stablu ispod kataloga dokumenta, dok rečnik stranice nosi /AF niz koji referencira istu file specification sa AFRelationship ključem, pa ClearPageAssociatedFiles otkačuje vezu a podatke ne uništava
Povezanost na nivou strane dodaje drugu referencu, ne drugi primerak: čitači koji znaju samo za priloge na nivou dokumenta i dalje nalaze payload u name stablu, a brisanje veze stranice ostavlja ugrađeni tok dostižnim

Ta funkcija ima jedan namerno uzan uslov za uspeh koji vredi znati. Uspeh prijavljuje samo kad stranica stvarno nosi /AF ključ. Stranica koja nikada nije imala povezanosti vraća neuspeh umesto vesele potvrde, pa pozivalac ne može no-op da uzme za završeno čišćenje

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

    // Kači seriju merenja koja je proizvela grafikon na strani 3
    Idx := Lib.AddPageAssociatedFileFromFile(3,
      'series-03.csv',            // datoteka na disku
      'measurements.csv',         // ime za prikaz unutar PDF-a
      'text/csv',                 // MIME tip
      '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;

String odnosa u praksi nije slobodan tekst. ISO 32000-2 definiše vokabular, Source, Data, Alternative, Supplement, EncryptedPayload, FormData, Schema i Unspecified, i potrošači se oslanjaju na njega. Data za brojeve iza grafikona, Source za dokument iz kojeg je stranica generisana, Alternative za ekvivalentan prikaz. Birajte iz vokabulara i kad još ništa u vašem pipeline-u ne čita taj ključ, jer sledeća alatka u lancu možda hoće

Zašto isto traženje treba FollowRef u oba smera?

Zato što praćenje referenci odgovara na dva različita pitanja, i kod mora da zna koje od njih postavlje. Traženje ključa koje prati indirektne reference vraća objekat na koji referenca pokazuje. Traženje koje ne prati vraća samu referencu. Oba su ispravna, a pogrešan izbor proizvodi tiho pogrešno ponašanje umesto grešku

Čitanje povezane datoteke pokazuje prvi smer. Da biste dobili broj objekta ugrađenog toka iza /EF i /F ključeva file specification-a, traženje ne sme da prati, jer praćenje razrešuje referencu u sam objekat toka i broj objekta nestaje. Pravilo se generališe: svaki kod koji treba identitet objekta, a ne njegov sadržaj, mora da uzme sirovu referencu

Optional content pokazuje suprotan smer, i taj je koštao više da se pronađe. Rečnik svojstava optional content-a upisuje se u katalog kao indirektan objekat, pa kod koji ga čita nazad bez praćenja dobija referencu umesto rečnika. Provera tipa na toj vrednosti tada pada, i prirodna fallback grana — ako konfiguracije nema, napravi je — proradi i prepiše konfiguraciju koja je već tamo stajala. Ništa ne baca izuzetak. Slojevi opisani u optional content grupama i slojevima jednostavno izgube svoje podrazumevano stanje vidljivosti

Lekcija se generališe van oba slučaja. Kad traženje može da vrati ili referencu ili objekat, gola provera tipa nije obrada greške: to je grana koja će jednom biti uzeta iz pogrešnog razloga. Odlučite eksplicitno šta svako mesto poziva treba i dajte prednost javnom API-ju koji na pitanje odgovara direktno, poput svojstva koja broji optional content grupe, umesto da zadirate u zaštićen pristupnik za katalog rečnik

Mapa odlučivanja za praćenje referenci u PDF traženjima kako je realizovano u PDFlibPas-u: čitanje /EF i /F ispod file specification-a ne sme da prati referencu jer je odgovor broj objekta ugrađenog toka, dok indirektan /OCProperties rečnik u katalogu mora da se prati ili će pala provera tipa tiho prepisati postojeću optional content konfiguraciju
Isto traženje odgovara na dva različita pitanja: identitet treba sirovu referencu, sadržaj razrešen objekat, i gola provera tipa umesto te odluke jednom pokrene pogrešnu granu bez ijednog izuzetka
// Prilozi na nivou dokumenta i povezanosti na nivou strane koegzistiraju.
// Ugrađena datoteka može biti označena i kao povezana na nivou dokumenta
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));

// Brisanje otkačuje vezu stranice; payload ostaje u name stablu
if Lib.ClearPageAssociatedFiles(3) > 0 then
  Writeln('page 3 associations removed, payloads still reachable');

Šta conformance režimi rade prilozima

Arhivski profili ograničavaju šta sme da se ugradi, i to ograničenje se sprovodi na ulaznoj tački, a ne u trenutku čuvanja. PDF/A-1 ugrađene datoteke zabranjuje u potpunosti, PDF/A-2 dopušta samo ugrađene PDF/A dokumente, a PDF/A-3 je profil koji je ugrađivanje otvorio za proizvoljne tipove datoteka, i upravo zato hibridni formati faktura počivaju na njemu

PDFlibPas odbija prilog kad ga aktivni conformance režim ne dopušta, na samom pozivu, a ne stotine operacija kasnije tokom izlaza. To je namerna odluka o tome gde je grešku najjeftinije obraditi: odbijanje na mestu poziva imenuje datoteku koju ste dodavali, dok odbijanje pri čuvanju imenuje dokument i ostavlja vas da ishodujete koji od četrdeset priloga je kriv

Zato se povezane datoteke i pojavljuju toliko često u elektronskom fakturisanju. Hibridna faktura je PDF koji čovek čita, sa mašinski čitljivim XML payload-om zakačenim i označenim pravim odnosom, i profil kontejnera i ključ odnosa deo su specifikacije, a ne konvencije. Ta konstrukcija je obrađena u članku o izgradnji Factur-X i ZUGFeRD hibridnih faktura, a metapodaci u PDF/A-3 XMP extension šemi

Kada povezanost treba da bude po strani, a ne po dokumentu?

Kad potrošač treba da zna kojoj strani podaci pripadaju, i samo tada. Prilozi na nivou dokumenta su jednostavniji, šire podržani od pregledača i dovoljni kad god payload opisuje ceo dokument: XML fakture, manifest potpisa, arhiva izvora. Do povezanosti na nivou strane posežite kad je payload zaista opsegom vezan za stranu i kad je identitet strane deo njegovog značenja

Podrška je praktično ograničenje. Datoteke povezane na nivou strane su konstrukcija iz PDF 2.0, i podrška u pregledačima je tanja nego za priloge na nivou dokumenta. Pošto payload u svakom slučaju sedi u name stablu, pregledač koji ignoriše /AF na stranama i dalje prikazuje datoteku u spisku priloga, pa propadanje ide blago. Ali ako je veza sa stranom suštinska za vašeg potrošača, a ne koristan metapodatak, proverite čitač kog stvarno targetirate umesto da pretpostavljate

Datoteke povezane na nivou strane, prilozi na nivou dokumenta i arhivsko-profilna vrata koja upravljaju obojim stižu uz PDFlibPas Delphi PDF biblioteku. Ako pri ulazu istovremeno i popravljate starije datoteke, rad na metapodacima i conformance-u iz konverzije u PDF/A uz popravku metapodataka je ono što odlučuje koja je od ovih putanja za priloge vama uopšte dostupna