Prílohy súborov PDF sa ukladajú do stromu vložených súborov dokumentu, čo je štruktúra, ktorú väčšina prehliadačov zobrazuje ako panel so sponkou alebo ako bočný panel príloh. Z kódu v Delphi sprístupňuje PDFium Component tento strom prostredníctvom malej sady indexovaných vlastností triedy TPdf: prechádzate ich pomocou celočíselného indexu, čítate názvy a polia bajtov, vytvárate nové položky a mažete tie existujúce. Rozhranie API je úzke; pred písaním produkčného kódu stojí za to spoznať niekoľko obmedzení poradia a jedno pravidlo na ošetrenie ciest
Čítanie príloh z otvoreného dokumentu
Vlastnosť AttachmentCount udáva počet vložených súborov, ktoré dokument deklaruje. Číta sa priamo z podkladového volania PDFium, takže odráža iba to, čo PDF skutočne obsahuje. Vlastnosť AttachmentName[Index] potom vracia zobrazovaný názov ako WString a indexovaná vlastnosť Attachment[Index] poskytuje čisté bajty vo forme poľa TBytes. Obe vlastnosti sú indexované od nuly. Pred dopytovaním na ktorúkoľvek z nich musí byť dokument otvorený (Pdf.Active = True); volanie nad zatvoreným dokumentom vráti nulu alebo prázdny výsledok bez vyvolania výnimky
Na jednu vec netreba zabúdať: vlastnosť Attachment[Index] pri každom čítaní alokuje a vracia kompletný obsah súboru. Pri dokumente, ktorý nesie veľký vložený objekt, znamená prechádzanie všetkých príloh na vytvorenie zoznamu zaplatenie nákladov na alokáciu pri každom volaní. Ak potrebujete iba názvy na zobrazenie v zozname, prečítajte najprv AttachmentName a načítanie bajtov odložte až na moment, keď používateľ súbor skutočne vyžiada
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;
Uloženie prílohy na disk
K dispozícii nie je žiadna pomocná metóda SaveAttachment. Bajty prečítate a zapíšete ich kamkoľvek potrebujete, čo znamená, že zostavenie cesty a jej ošetrenie (sanitization) leží plne na vašom kóde. Je to dôležité najmä vtedy, keď názvy príloh pochádzajú z nedôveryhodných dokumentov. Názvy príloh PDF sú reťazce uložené vo vnútri súboru; môžu obsahovať oddeľovače ciest, podobné Unicode znaky a iné symboly, ktoré prinesú neočakávané výsledky, ak ich priamo odovzdáte do TFileStream.Create. Pred zostavením akejkoľvek výstupnej cesty vždy preveďte názov cez funkciu ExtractFileName a zvážte odmietnutie názvov, ktoré začínajú bodkou alebo obsahujú znaky, ktoré váš systém neočakáva
Pole bajtov vrátené vlastnosťou Attachment[Index] vlastní volajúci kód. Zapíšte ho pomocou bežného TFileStream a môžete s ním nakladať podľa uváženia, vrátane kontroly prvých niekoľkých bajtov na overenie skutočného formátu súboru namiesto slepej dôvery voči deklarovanému názvu
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;
Pridávanie príloh a dvojstupňový zápis
Vytvorenie prílohy si vyžaduje dve volania a nie jedno. CreateAttachment(Name) zaregistruje novú položku v strome vložených súborov a pri úspechu vráti True. Táto položka je na začiatku prázdna. Obsah jej potom priradíte zápisom do vlastnosti Attachment[AttachmentCount - 1], čím zacielite na posledný vytvorený záznam. Ak CreateAttachment vráti False, položka sa nevytvorila a zápis by poškodil prílohu na indexe, ktorý je zhodou okolností aktuálne posledný
Po úprave zoznamu príloh existujú zmeny iba v pamäti. Zavolajte SaveAs na zápis nového súboru s aktualizovaným stromom vložených súborov. PDFium Component momentálne nepodporuje ukladanie priamo do rovnakého, aktuálne otvoreného súboru, pretože engine si udržiava otvorený popisovač (handle) na čítanie zdroja. Štandardným postupom pre aktualizáciu na mieste je uloženie do dočasnej cesty, zatvorenie dokumentu, vymazanie alebo premenovanie originálu, premenovanie dočasného súboru na pôvodné miesto a jeho opätovné otvorenie
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;
Informácie o type prílohy
Okrem názvu a obsahu bajtov vracia vlastnosť AttachmentType[Index] reťazec typu MIME uložený v slovníku vloženého súboru PDF, ak bol pri pôvodnom pripojení zaznamenaný. Mnohé generátory nechávajú toto pole prázdne alebo ho nastavujú na univerzálnu hodnotu ako application/octet-stream, takže sa naň v produkčnej linke nemôžete spoliehať pri určovaní formátu. Pre spoľahlivú identifikáciu prečítajte prvých niekoľko bajtov obsahu a overte známe signatúry súborov: %PDF pre vnorené PDF, hlavičku lokálneho ZIP súboru PK\x03\x04 pre dokumenty Office Open XML, \xD0\xCF\x11\xE0 pre staršie binárne formáty compound file. Informácia o type zo slovníka je vhodná na zobrazenie v rozhraní, no nemala by riadiť spracovanie, keď máte k dispozícii skutočné bajty
Mazanie príloh
Metóda DeleteAttachment(Index) odstráni položku na danej pozícii a pri úspechu vráti True. Po vymazaní sa zostávajúce položky posunú nadol, takže ak vymazávate viacero príloh v cykle, musíte postupovať od posledného indexu smerom nadol a nie nahor, aby ste sa vyhli preskakovaniu položiek po každom posune. Zmena sa prejaví iba v pamäti, kým nezavoláte SaveAs
Častým scenárom v systémoch na spracovanie dokumentov je odstránenie všetkých príloh z prichádzajúceho PDF pred jeho ďalším odoslaním, a to z bezpečnostných dôvodov alebo kvôli zníženiu veľkosti. Zistite počet pred cyklom a prechádzajte ním odzadu:
procedure StripAllAttachments(Pdf: TPdf);
var
I: Integer;
begin
for I := Pdf.AttachmentCount - 1 downto 0 do
Pdf.DeleteAttachment(I);
end;
Kde sa prílohy PDF vyskytujú v praxi
Norma PDF/A-3 (ISO 19005-3) výslovne povoľuje vyhovujúce vložené súbory ako mechanizmus na pribalenie zdrojových dát k archívnej verzii; elektronické faktúry ZUGFeRD a Factur-X sa spoliehajú presne na toto, aby vložili štruktúrovaný XML obsah priamo do ľudsky čitateľného vzhľadu PDF. Dokumenty PDF vytvorené z e-mailov niekedy nesú svoje pôvodné prílohy správ prenesené do tohto stromu vložených súborov. Technická dokumentácia pochádzajúca zo štruktúrovaných publikačných systémov občas podobným spôsobom pribaluje sprievodné podklady
Keď vaša aplikácia spracováva prichádzajúce PDF zvonku, kontrola vlastnosti AttachmentCount v rámci príjmu dokumentu stojí za zváženie z dvoch nezávislých dôvodov. Po prvé, vložené súbory môžu niesť dáta, ktoré chcete extrahovať a spracovať, ako napríklad XML vo vnútri faktúry PDF. Po druhé, vložené súbory môžu niesť ľubovoľný spustiteľný obsah, takže informácia o ich prítomnosti je dôležitá aj vtedy, keď ich nikdy neplánujete extrahovať. Ani jeden z týchto dôvodov si nevyžaduje nič zložité: prečítajte počet, skontrolujte názvy a rozhodnite sa, ako naložíte s bajtmi
Vlastnosti príloh zobrazené v tomto článku sú súčasťou produktu PDFium Component pre Delphi a C++Builder