PDFlibPas prikačuje ugrađenu datoteku uz jednu konkretnu stranicu umjesto uz dokument u cjelini, tako da upiše /AF array u rječnik stranice dok payload ostaje registriran u EmbeddedFiles name tree dokumenta. Ta podjela je ono što ISO 32000-2 §14.13 opisuje, i to je ono što čitaču omogućuje da odgovori na pitanje koje prilog na razini dokumenta ne može: kojoj stranici ti podaci pripadaju
Primjene su specifičnije od općih priloga. Izvještaj o snimanju terena gdje svaka stranica nosi sirovi niz mjerenja iza svog grafikona. Skenirana serija gdje svaka stranica čuva OCR rezultat koji je proizveo njezin sloj teksta. Skup nacrta gdje svaki list nosi CAD izvod iz kojeg je renderiran. U svakom od tih slučajeva popis priloga na razini dokumenta bio bi hrpa datoteka čija imena kodiraju brojeve stranica, a to je konvencija, a ne struktura
Jedan payload, dva mjesta s kojih se na njega referencira
Važna strukturna točka je da asocijacija na razini stranice ne stvara drugu kopiju bilo čega. Datoteka se ugrađuje jednom i registrira u EmbeddedFiles name tree točno kao što to čini prilog na razini dokumenta, koristeći isti file specification mehanizam. Razlikuje se mjesto gdje se upisuju referenca i njezin relationship ključ: u rječnik stranice umjesto u katalog dokumenta
Slijede dvije posljedice. Prvo, čitač koji zna samo za priloge na razini dokumenta i dalje nalazi payload, jer je on u name tree gdje takav čitač traži. Drugo, brisanje asocijacije stranice uklanja vezu, a ne datoteku. ClearPageAssociatedFiles odvaja stranicu od njezinih associated datoteka i ostavlja payload dohvatljivima kroz name tree, a to je konzervativno ponašanje: operacija koja kaže očisti asocijaciju ne bi tiho trebala uništiti podatke na koje se drugi dio dokumenta možda referencira
Ta funkcija ima jedan namjerno uzak uvjet uspjeha koji vrijedi znati. Uspjeh prijavljuje samo kada stranica zaista nosi /AF ključ. Stranica koja nikad nije imala asocijacije vraća neuspjeh umjesto vesele potvrde, pa pozivatelj ne može no-op zamijeniti za dovršeno čišćenje
var
Lib: TPDFlib;
Idx, I: Integer;
begin
Lib := TPDFlib.Create(nil);
try
Lib.LoadFromFile('survey-report.pdf');
// Prikači niz mjerenja koji je proizveo grafikon na stranici 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;
Relationship string u praksi nije slobodan tekst. ISO 32000-2 definira vokabular, Source, Data, Alternative, Supplement, EncryptedPayload, FormData, Schema i Unspecified, i potrošači se na njega oslanjaju. Data za brojeve iza grafikona, Source za dokument iz kojega je stranica generirana, Alternative za ekvivalentnu reprezentaciju. Birajte iz vokabulara i kad još ništa u vašem pipelineu to ne čita, jer sljedeći alat u lancu možda hoće
Zašto isti lookup treba FollowRef u oba smjera?
Zato praćenje referenci odgovara na dva različita pitanja, i kod mora znati koje od njih postavlja. Lookup ključa koji prati indirektne reference vraća objekt na koji referenca pokazuje. Lookup koji ne prati vraća samu referencu. Oboje je ispravno, i korištenje pogrešnog proizvodi tiho pogrešno ponašanje umjesto greške
Čitanje associated datoteke pokazuje prvi smjer. Da biste dobili object number ugrađenog streama iza file specification /EF i /F ključeva, lookup ne smije pratiti, jer praćenje razriješi referencu u stream objekt i object number je nestao. Pravilo se generalizira: svaki kodni put kojem treba identitet objekta, a ne njegov sadržaj, mora uzeti sirovu referencu
Optional content pokazuje suprotni smjer, i koštao je više da se pronađe. Rječnik svojstava optional contenta upisuje se u katalog kao indirektni objekt, pa kod koji ga čita nazad bez praćenja dobiva referencu umjesto rječnika. Provjera tipa nad tom vrijednošću tada padne, i prirodna fallback grana, ako nema konfiguracije stvori jednu, se izvrši i pregazi konfiguraciju koja je već bila tamo. Ništa ne baca iznimku. Slojevi opisani u optional content grupama i slojevima jednostavno izgube svoje zadano stanje vidljivosti
Lekcija se generalizira iza oba slučaja. Kada lookup može vratiti ili referencu ili objekt, gola provjera tipa nije rukovanje greškama: to je grana koja će jednog dana biti uzeta iz pogrešnog razloga. Odlučite izrijekom što svako mjesto poziva treba, i radije birajte javni API koji na pitanje odgovara izravno, poput propertyja koji broji optional-contente, nego zaranjanje u protected accessor za rječnik kataloga
// Prilozi na razini dokumenta i asocijacije na razini stranice koegzistiraju.
// Ugrađena datoteka može biti označena kao associated i na razini 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 odvaja vezu stranice; payload ostaje u name tree
if Lib.ClearPageAssociatedFiles(3) > 0 then
Writeln('page 3 associations removed, payloads still reachable');
Što conformance načini rade s prilozima
Arhivski profili ograničavaju što se smije ugraditi, i to ograničenje se provodi na ulaznoj točki, a ne u trenutku spremanja. 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 otvorio ugrađivanje za proizvoljne tipove datoteka, i upravo zato se na njemu grade hibridni formati računa
PDFlibPas odbija prilog kada aktivni conformance način to ne dopušta, na pozivu, a ne stotine operacija kasnije tijekom ispisa. To je namjerni izbor o tome gdje je grešku najjeftinije adresirati: odbijanje na mjestu poziva imenuje datoteku koju ste dodavali, dok odbijanje u trenutku spremanja imenuje dokument i ostavlja vas da ispitujete koji je od četrdeset priloga uzrok
Zato se associated datoteke i pojavljuju tako često u elektroničkom fakturiranju. Hibridni račun je PDF koji čovjek čita, s mašinski čitljivim XML payloadom prikačenim i označenim pravim relationshipom, i kontejnerski profil i relationship ključ dio su specifikacije, a ne konvencije. Ta izgradnja pokrivena je u izgradnji Factur-X i ZUGFeRD hibridnih računa, a metadata strana u PDF/A-3 XMP extension schemi
Kada asocijacija treba biti po stranici, a ne po dokumentu?
Kada potrošač treba znati kojoj stranici podaci pripadaju, i samo tada. Prilozi na razini dokumenta su jednostavniji, šire podržani od preglednika i dovoljni kad god payload opisuje cijeli dokument, XML računa, manifest potpisa, arhivu izvora. Za asocijaciju na razini stranice posežite kada je payload zaista opsegom vezan uz stranicu i identitet stranice je dio njegova značenja
Podrška je praktično ograničenje. Associated datoteke na razini stranice su konstrukcija iz PDF 2.0, i podrška u preglednicima je tanja nego za priloge na razini dokumenta. Budući da payload u svakom slučaju sjedi u name tree, preglednik koji ignorira /AF na stranicama i dalje pokazuje datoteku u svom popisu priloga, pa je degradacija graciozna. Ali ako je veza sa stranicom bitna za vašeg potrošača, a ne samo koristan metadata, provjerite čitač koji stvarno ciljate umjesto da pretpostavljate
Associated datoteke na razini stranice, prilozi na razini dokumenta i arhivski profilni gateovi koji upravljaju obojima dolaze uz PDFlibPas Delphi PDF biblioteku. Ako usput popravljate i starije datoteke pri unosu, rad na metadati i conformanceu u pretvorbi u PDF/A s popravkom metadate je ono što odlučuje koja je od ovih ruta priloga vama uopće dostupna