PDF privitci datoteka pohranjeni su u stablu ugrađenih datoteka dokumenta, strukturi koju većina preglednika prikazuje kao ploču sa spajalicom ili bočnu traku s privitcima. Iz Delphi koda, PDFium VCL izlaže to stablo kroz mali skup indeksiranih svojstava na TPdf: iterirate po cjelobrojnom indeksu, čitate nazive i bajtove sadržaja, stvarate nova mjesta i brišete postojeća. API površina je uska; postoji samo nekoliko ograničenja u pogledu redoslijeda i jedno pravilo čišćenja staza koje je vrijedno znati prije nego što napišete produkcijski kod za to.
Čitanje privitaka iz otvorenog dokumenta
Svojstvo AttachmentCount daje broj ugrađenih datoteka koje dokument deklarira. Ono čita izravno iz temeljnog poziva PDFium-a, tako da odražava samo ono što PDF zapravo sadrži. Od tuda, AttachmentName[Index] vraća prikazano ime kao WString, a Attachment[Index] isporučuje sirove bajtove kao polje TBytes. Oba su indeksirana od nule. Dokument mora biti otvoren (Pdf.Active := True) prije nego što zatražite bilo koje svojstvo; njihov poziv na zatvorenom dokumentu daje nulu ili prazan rezultat bez iznimke.
Jedna stvar koju treba imati na umu: Attachment[Index] alocira i vraća puni sadržaj datoteke pri svakom čitanju. Za dokument koji nosi veliku ugrađenu datoteku, iteriranje kroz sve privitke radi izgradnje popisa za prikaz znači plaćanje tog troška alokacije pri svakom pozivu. Ako trebate samo nazive za potrebe prikaza, prvo pročitajte AttachmentName i odgodite dohvaćanje bajtova dok korisnik stvarno ne zatraži datoteku.
procedure ListAttachments(Pdf: TPdf);
var
I: Integer;
Data: TBytes;
begin
if not Pdf.Active then
Exit;
for I := 0 to Pdf.AttachmentCount - 1 do
begin
Data := Pdf.Attachment[I];
Writeln(Format('%d: %s (%d bytes)',
[I, Pdf.AttachmentName[I], Length(Data)]));
end;
end;
Ekstrakcija privitka na disk
Ne postoji pomoćna metoda poput SaveAttachment. Vi čitate bajtove i zapisujete ih gdje god vam je potrebno, što konstrukciju i čišćenje staze u potpunosti stavlja na vaš kod. To je važno kada nazivi privitaka dolaze iz nepouzdanih dokumenata. Nazivi PDF privitaka su nizovi znakova pohranjeni unutar datoteke; mogu sadržavati separatore staza, Unicode sličnosti i druge znakove koji će proizvesti neočekivane rezultate ako ih proslijedite izravno metodi TFileStream.Create. Uvijek propustite naziv kroz ExtractFileName prije izrade bilo koje izlazne staze i razmislite o odbacivanju naziva koji počinju točkom ili sadrže znakove izvan onoga što vaš sustav očekuje.
Polje bajtova koje vraća Attachment[Index] je u vlasništvu pozivatelja. Zapišite ga s uobičajenim TFileStream i možete raditi s njim što god želite, uključujući provjeru prvih nekoliko bajtova radi provjere stvarnog formata datoteke umjesto da vjerujete deklariranom nazivu.
procedure ExtractAttachment(Pdf: TPdf; Index: Integer; const OutputDir: string);
var
SafeName: string;
OutPath: string;
Data: TBytes;
FS: TFileStream;
begin
SafeName := ExtractFileName(Pdf.AttachmentName[Index]);
if SafeName = '' then
SafeName := Format('attachment_%d', [Index]);
OutPath := IncludeTrailingPathDelimiter(OutputDir) + SafeName;
Data := Pdf.Attachment[Index];
FS := TFileStream.Create(OutPath, fmCreate);
try
if Length(Data) > 0 then
FS.WriteBuffer(Data[0], Length(Data));
finally
FS.Free;
end;
end;
Dodavanje privitaka i pisanje u dva koraka
Stvaranje privitka zahtijeva dva poziva, a ne jedan. CreateAttachment(Name) registrira novo mjesto u stablu ugrađenih datoteka i vraća True u slučaju uspjeha. To mjesto započinje prazno. Zatim dodjeljujete sadržaj pisanjem u Attachment[AttachmentCount - 1], ciljajući zadnji stvoreni unos. Ako CreateAttachment vrati False, mjesto nije stvoreno i dodjela bi oštetila privitak na indeksu koji se slučajno nalazi kao posljednji.
Nakon izmjene popisa privitaka, promjene žive samo u memoriji. Pozovite SaveAs za zapisivanje nove datoteke s ažuriranim stablom ugrađenih datoteka. PDFium VCL trenutno ne podržava spremanje natrag u istu datoteku koja je trenutno otvorena, cuz motor drži ručku za čitanje izvora. Standardni obrazac za lokalno ažuriranje je spremanje na privremenu stazu, zatvaranje dokumenta, brisanje ili preimenovanje originala, a zatim preimenovanje privremene datoteke na njezino mjesto i ponovno otvaranje.
procedure AddFileAttachment(Pdf: TPdf; const FilePath: string);
var
FS: TFileStream;
Data: TBytes;
AttachName: string;
begin
if not Pdf.Active then
Exit;
FS := TFileStream.Create(FilePath, fmOpenRead or fmShareDenyWrite);
try
SetLength(Data, FS.Size);
if FS.Size > 0 then
FS.ReadBuffer(Data[0], FS.Size);
finally
FS.Free;
end;
AttachName := ExtractFileName(FilePath);
if Pdf.CreateAttachment(AttachName) then
Pdf.Attachment[Pdf.AttachmentCount - 1] := Data;
end;
Informacije o vrsti privitka
Osim naziva i sadržaja u bajtovima, AttachmentType[Index] vraća niz MIME vrste pohranjen u rječniku ugrađene datoteke PDF-a, ako je bio zabilježen kada je datoteka prvotno priložena. Mnogi generatori ostavljaju ovo polje praznim ili ga postavljaju na generičku vrijednost poput application/octet-stream, tako da se ne možete osloniti na njega za otkrivanje formata u produkcijskom cjevovodu. Za pouzdanu identifikaciju, pročitajte prvih nekoliko bajtova sadržaja i provjerite poznate potpise datoteka: %PDF za ugniježđeni PDF, ZIP zaglavlje lokalne datoteke PK\x03\x04 za Office Open XML dokumente, \xD0\xCF\x11\xE0 za stare binarne datoteke složenih datoteka. Informacije o vrsti iz rječnika su u redu za prikaz na oznaci korisničkog sučelja, ali ne bi trebale upravljati odlukama o obradi kada su vam dostupni stvarni bajtovi.
Brisanje privitaka
Metoda DeleteAttachment(Index) uklanja unos na toj poziciji i vraća True u slučaju uspjeha. Nakon brisanja, preostali unosi se pomiču prema dolje, pa ako brišete više privitaka u petlji, morate iterirati od posljednjeg indeksa prema dolje, a ne prema naprijed, kako biste izbjegli preskakanje unosa nakon svakog pomicanja. Promjena je u memoriji sve dok ne pozovete SaveAs.
Uobičajeni scenarij u cjevovodima za obradu dokumenata je uklanjanje svih privitaka iz dolaznog PDF-a prije nego što se proslijedi dalje, iz sigurnosnih razloga ili razloga veličine. Izbrojite jednom prije petlje i iterirajte unatrag:
procedure StripAllAttachments(Pdf: TPdf);
var
I: Integer;
begin
for I := Pdf.AttachmentCount - 1 downto 0 do
Pdf.DeleteAttachment(I);
end;
Gdje se PDF privitci pojavljuju u praksi
API za privitke radi na bilo kojem PDF-u koji PDFium može otvoriti, ali dokumenti u kojima stvarno nailazite na ugrađene datoteke grupiraju se oko nekoliko specifičnih slučajeva. PDF/A-3 (ISO 19005-3) eksplicitno dopušta sukladne ugrađene datoteke kao mehanizam za pakiranje izvornih podataka uz arhivsku verziju; elektronički računi ZUGFeRD i Factur-X oslanjaju se upravo na to za ugradnju strukturiranog XML sadržaja unutar ljudima čitljivog PDF rasporeda. PDF-ovi izvedeni iz e-pošte ponekad nose svoje izvorne privitke poruka proslijeđene u stablo ugrađenih datoteka. Tehnička dokumentacija koja potječe iz strukturiranih sustava za autorizaciju povremeno pakira prateće resurse na isti način.
Kada vaša aplikacija obrađuje dolazne PDF-ove izvan vaše organizacije, provjera svojstva AttachmentCount kao dijela unosa dokumenata korisna je iz dva neovisna razloga. Prvo, ugrađene datoteke mogu nositi podatke koje želite izdvojiti i obraditi, kao što je XML unutar PDF računa. Drugo, ugrađene datoteke mogu nositi proizvoljan izvršni sadržaj, pa je poznavanje onoga što je prisutno važno čak i ako ga nikada ne namjeravate izdvojiti. Nijedan razlog ne zahtijeva od vas ništa komplicirano: pročitajte broj, provjerite nazive i odlučite što ćete učiniti s bajtovima.
Svojstva privitaka prikazana ovdje dio su komponente PDFium VCL component za Delphi i C++Builder.