PDF-filbilagor lagras i dokumentets inbäddade filträd, en struktur som de flesta visare uppvisar som en gem-panel eller ett sidofält för bilagor. Från Delphi-kod exponerar PDFium Component det trädet genom en liten uppsättning indexerade egenskaper på TPdf: du itererar via heltalsindex, läser namn och byte-laster, skapar nya platser och tar bort befintliga. API-ytan är smal; det finns bara ett fåtal ordningsbegränsningar och en saneringsregel värd att veta innan du skriver produktionskod runt den
Att läsa bilagor från ett öppet dokument
AttachmentCount anger antalet inbäddade filer som dokumentet deklarerar. Den läser direkt från PDFiums underliggande anrop, så den återspeglar bara vad PDF:en faktiskt innehåller. Därifrån returnerar AttachmentName[Index] visningsnamnet som en WString, och Attachment[Index] levererar de råa byten som en TBytes-array. Båda är nollbaserade. Dokumentet måste vara öppet (Pdf.Active = True) innan du frågar efter någon egenskap; att anropa dem på ett stängt dokument ger dig noll eller ett tomt resultat utan något undantag
En sak att tänka på: Attachment[Index] allokerar och returnerar hela filens last vid varje läsning. För ett dokument som bär på en stor inbäddad resurs innebär iteration genom alla bilagor för att bygga en visningslista att du betalar den allokeringskostnaden vid varje anrop. Om du bara behöver namn i visningssyfte, läs AttachmentName först och skjut upp byte-hämtningen tills användaren faktiskt begär 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;
Extrahera en bilaga till disk
Det finns ingen SaveAttachment-hjälpare. Du läser byten och skriver dem var du än behöver, vilket lägger sökvägskonstruktion och sanering helt på din kod. Det spelar roll när bilagenamn kommer från opålitliga dokument. PDF-bilagenamn är strängar lagrade inuti filen; de kan innehålla sökvägsavgränsare, Unicode-lookalikes och andra tecken som kommer att producera oväntade resultat om du skickar dem direkt till TFileStream.Create. Kör alltid namnet genom ExtractFileName innan du bygger någon utdatasökväg, och överväg att avvisa namn som börjar med en punkt eller innehåller tecken utöver vad ditt system förväntar sig
Byte-arrayen som returneras av Attachment[Index] ägs av anroparen. Skriv ut den med en normal TFileStream så är den din att göra vad du vill med, inklusive att inspektera de första byten för att verifiera det faktiska filformatet snarare än att lita på det deklarerade namnet
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;
Lägga till bilagor och tvåstegsskrivningen
Att skapa en bilaga tar två anrop, inte ett. CreateAttachment(Name) registrerar en ny plats i det inbäddade filträdet och returnerar True vid framgång. Den platsen börjar tom. Du tilldelar sedan lasten genom att skriva till Attachment[AttachmentCount - 1], vilket riktar in sig på den senast skapade posten. Om CreateAttachment returnerar False, skapades inte platsen och tilldelningen skulle korrumpera bilagan vid det index som råkar vara sist
Efter att ha modifierat bilagelistan lever ändringarna enbart i minnet. Anropa SaveAs för att skriva en ny fil med det uppdaterade inbäddade filträdet. PDFium Component stöder inte att spara tillbaka till samma fil som för närvarande är öppen, eftersom motorn håller ett läshandtag till källan. Standardmönstret för en uppdatering på plats är att spara till en tillfällig sökväg, stänga dokumentet, ta bort eller byta namn på originalet, och sedan byta namn på temp-filen till dess plats och öppna igen
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;
Typsinformation för bilagor
Utöver namnet och byte-lasten, returnerar AttachmentType[Index] MIME-typsträngen lagrad i PDF:ens inbäddade filordlista, om en sådan spelades in när filen ursprungligen bifogades. Många generatorer lämnar det här fältet tomt eller sätter det till ett generiskt värde som application/octet-stream, så du kan inte förlita dig på det för formatdetektering i en produktions-pipeline. För tillförlitlig identifiering, läs de första byten av lasten och kontrollera efter kända filsignaturer: %PDF för en kapslad PDF, ZIP-lokalfilhuvudet PK\x03\x04 för Office Open XML-dokument, \xD0\xCF\x11\xE0 för äldre compound-file-binärer. Typinformation från ordlistan går bra att exponera i en UI-etikett, men bör inte styra bearbetningsbeslut när du har de faktiska byten tillgängliga
Ta bort bilagor
DeleteAttachment(Index) tar bort posten på den positionen och returnerar True vid framgång. Efter borttagning flyttas de återstående posterna ner, så om du tar bort flera bilagor i en loop måste du iterera från det sista indexet och nedåt, inte framåt, för att undvika att hoppa över poster efter varje flyttning. Ändringen är i minnet tills du anropar SaveAs
Ett vanligt scenario i pipelines för dokumentbearbetning är att rensa bort alla bilagor från en inkommande PDF innan den skickas vidare nedströms, av säkerhets- eller storleksskäl. Räkna en gång före loopen och iterera baklänges:
procedure StripAllAttachments(Pdf: TPdf);
var
I: Integer;
begin
for I := Pdf.AttachmentCount - 1 downto 0 do
Pdf.DeleteAttachment(I);
end;
Var PDF-bilagor dyker upp i praktiken
API:et för bilagor fungerar på alla PDF-filer som PDFium kan öppna, men de dokument där du faktiskt stöter på inbäddade filer kretsar kring några specifika fall. PDF/A-3 (ISO 19005-3) tillåter uttryckligen inbäddade filer som följer standarden som en mekanism för att bunta källdata vid sidan av arkivåtergivningen; elektroniska fakturor enligt ZUGFeRD och Factur-X förlitar sig på exakt detta för att bädda in en strukturerad XML-last inuti den mänskligt läsbara PDF-layouten. E-posthärledda PDF-filer bär ibland sina ursprungliga meddelandebilagor vidarebefordrade in i det inbäddade filträdet. Teknisk dokumentation som har sitt ursprung i strukturerade författarsystem buntar ibland stödjande resurser på samma sätt
När din applikation bearbetar inkommande PDF-filer utifrån din organisation är det värt att kontrollera AttachmentCount som en del av dokumentintaget av två oberoende skäl. För det första kan inbäddade filer bära data du vill extrahera och bearbeta, som XML inuti en faktura-PDF. För det andra kan inbäddade filer bära godtyckligt körbart innehåll, så det är viktigt att veta vad som finns närvarande även när du aldrig har för avsikt att extrahera det. Inget av skälen kräver att du gör något komplicerat: läs antalet, kontrollera namnen och bestäm vad du ska göra med byten
Bilageegenskaperna som visas här är en del av PDFium Component för Delphi och C++Builder