PDF-filvedlegg lagres i dokumentets innebygde-filtre (embedded-file tree), en struktur som de fleste visningsprogrammer viser frem (surfaces) som et binders-panel eller en vedlegg-sidefelt. Fra Delphi-kode eksponerer PDFium-komponenten det treet gjennom et lite sett med indekserte egenskaper på TPdf: du itererer med heltallsindeks, leser navn og byte-nyttelaster (byte payloads), oppretter nye plasser (slots), og sletter eksisterende. API-flaten (API surface) er smal; det er bare et par rekkefølgebegrensninger og én saneringsregel (sanitization rule) verdt å vite om før du skriver produksjonskode rundt det
Lese vedlegg fra et åpent dokument
AttachmentCount gir antallet innebygde filer dokumentet erklærer. Den leser direkte fra PDFiums underliggende oppkall, så den reflekterer bare det PDF-en faktisk inneholder. Derfra returnerer AttachmentName[Index] visningsnavnet som en WString, og Attachment[Index] leverer de rå bytene som en TBytes-array. Begge er null-baserte. Dokumentet må være åpent (Pdf.Active = True) før du spør (query) etter noen av egenskapene; å kalle dem på et lukket dokument gir deg null eller et tomt resultat uten noe unntak (exception)
Én ting å ha i bakhodet: Attachment[Index] tildeler (allocates) og returnerer den fulle filnyttelasten på hver lesing. For et dokument som bærer en stor innebygd ressurs, vil det å iterere gjennom alle vedlegg for å bygge en visningsliste bety at du betaler den tildelingskostnaden (allocation cost) på hvert oppkall. Hvis du bare trenger navn for visningsformål, les AttachmentName først og utsett (defer) bytehentingen (byte fetch) inntil brukeren faktisk ber om filen
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;
Trekke ut (Extracting) et vedlegg to disk
Det finnes ingen SaveAttachment-hjelper. Du leser bytene og skriver dem ut dit du trenger, noe som legger stikonstruksjon (path construction) og sanering fullt og helt på koden din. Det har betydning når vedleggsnavn kommer fra upålitelige dokumenter. PDF-vedleggsnavn er strenger lagret inni filen; de kan inneholde stiseparatorer (path separators), Unicode-lookalikes, og andre tegn som vil produsere uventede resultater hvis du sender dem direkte to TFileStream.Create. Kjør alltid navnet gjennom ExtractFileName før du bygger noen utdatasti (output path), og vurder å avvise navn som starter med et punktum eller inneholder tegn utenfor det systemet ditt forventer
Byte-arrayen returnert av Attachment[Index] er eiet av oppringeren (caller-owned). Skriv den ut med en vanlig TFileStream og den er din til å gjøre med som du vil, inkludert å inspisere de første bytene for å verifisere det faktiske filformatet fremfor å stole på det erklærte navnet
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;
Legge til vedlegg og to-trinns skrivingen
Å opprette et vedlegg krever to kall, ikke ett. CreateAttachment(Name) registrerer en ny plass (slot) i innebygde-filtreet (embedded-file tree) og returnerer True ved suksess. Den plassen starter tom. Deretter tilordner du nyttelasten (payload) ved å skrive til Attachment[AttachmentCount - 1], rettet mot den sist opprettede oppføringen (entry). Hvis CreateAttachment returnerer False, ble ikke plassen opprettet, og tilordningen ville korrumpere (corrupt) vedlegget ved uansett indeks som tilfeldigvis er sist
Etter modifisering av vedleggslisten, lever endringer bare i minnet. Kall SaveAs for å skrive en ny fil med det oppdaterte innebygde-filtreet. PDFium-komponenten støtter ikke lagring tilbake til den samme filen som for øyeblikket er åpen, fordi motoren holder et lesehåndtak (read handle) til kilden. Standardmønsteret for en oppdatering på stedet (in-place update) er å lagre til en midlertidig sti (temporary path), lukke dokumentet, slette eller gi nytt navn til originalen, og deretter gi nytt navn til den midlertidige filen slik at den kommer i posisjon og gjenåpne den
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;
Vedleggstype-informasjon
Utover navnet og byte-nyttelasten, returnerer AttachmentType[Index] MIME-typestrengen som er lagret i PDF-ens innebygde-fil-ordbok (embedded-file dictionary), hvis en ble registrert da filen opprinnelig ble lagt ved. Mange generatorer lar dette feltet stå tomt eller setter det til en generisk verdi som application/octet-stream, så du kan ikke stole på det for formatdeteksjon i en produksjons-arbeidsflyt. For pålitelig identifikasjon, les de første bytene av nyttelasten og sjekk etter kjente filsignaturer: %PDF for en innkapslet (nested) PDF, ZIP-lokal-fil-headeren PK\x03\x04 for Office Open XML-dokumenter, \xD0\xCF\x11\xE0 for eldre sammensatt-fil (compound-file) binærfiler. Typeinformasjon fra ordboken er fint å vise frem i en UI-etikett (UI label), men bør ikke drive behandlingsbeslutninger når du har de faktiske bytene tilgjengelig
Slette vedlegg
DeleteAttachment(Index) fjerner oppføringen på den posisjonen og returnerer True ved suksess. Etter sletting vil de gjenværende oppføringene skifte ned, så hvis du sletter flere vedlegg i en løkke, må du iterere fra den siste indeksen og nedover, ikke forover, for å unngå å hoppe over oppføringer etter hvert skift. Endringen er i minnet inntil du kaller SaveAs
Et vanlig scenario i dokumentbehandlings-arbeidsflyter er å fjerne alle vedlegg fra en innkommende PDF før den sendes videre, av sikkerhets- eller størrelsesgrunner. Tell én gang før løkken og iterer baklengs (in reverse):
procedure StripAllAttachments(Pdf: TPdf);
var
I: Integer;
begin
for I := Pdf.AttachmentCount - 1 downto 0 do
Pdf.DeleteAttachment(I);
end;
Hvor PDF-vedlegg dukker opp i praksis
Vedlegg-API-et fungerer på enhver PDF som PDFium kan åpne, men dokumentene der du faktisk støter på innebygde filer, grupperer seg rundt noen få spesifikke tilfeller. PDF/A-3 (ISO 19005-3) tillater eksplisitt samsvarende (conforming) innebygde filer som en mekanisme for å bunte (bundling) kildedata sammen med arkiv-gjengivelsen; ZUGFeRD og Factur-X elektroniske fakturaer baserer seg på akkurat dette for å bygge inn en strukturert XML-nyttelast inni det menneskelesbare (human-readable) PDF-oppsettet (PDF layout). E-post-avledede PDF-er bærer noen ganger med seg sine opprinnelige meldingsvedlegg videresendt inn i innebygde-filtreet. Teknisk dokumentasjon som stammer fra strukturerte forfattersystemer, bunter av og til støtteressurser på samme måte
Når applikasjonen din behandler innkommende PDF-er fra utenfor organisasjonen din, er det verdt å sjekke AttachmentCount som en del av dokumentinntaket (document intake) av to uavhengige grunner. For det første kan innebygde filer bære med seg data du ønsker å trekke ut og behandle, for eksempel XML inni en faktura-PDF. For det andre kan innebygde filer bære med seg vilkårlig kjørbart innhold, så å vite hva som er til stede har betydning selv når du aldri har til hensikt å trekke det ut. Ingen av grunnene krever at du gjør noe komplisert: les antallet, sjekk navnene, og bestem deg for hva du skal gjøre med bytene
Vedlegg-egenskapene vist her er en del av PDFium-komponenten for Delphi og C++Builder