PDF-filvedhæftninger gemmes i dokumentets indlejrede filtræ, en struktur, som de fleste fremvisere præsenterer som et papirclips-panel eller et sidepanel til vedhæftede filer. Fra Delphi-kode eksponerer PDFium Component dette træ gennem et lille sæt indeksere egenskaber på TPdf: Du itererer efter heltalsindeks, læser navne og byte-indholdspakker, opretter nye pladser og sletter eksisterende. API-fladen er smal; der er blot nogle få rækkefølge-begrænsninger og én stisaneringsregel, som er værd at kende, før du skriver produktionskode omkring det
Læsning af vedhæftte filer fra et åbent dokument
AttachmentCount angiver antallet af indlejrede filer, som dokumentet erklærer. Det læser direkte fra PDFium's underliggende kald, så det afspejler kun, hvad PDF'en faktisk indeholder. Derfra returnerer AttachmentName[Index] visningsnavnet som en WString, og Attachment[Index] leverer de rå bytes som et TBytes-array. Begge er nulbaserede. Dokumentet skal være åbent (Pdf.Active = True), før du forespørger på en af egenskaberne; at kalde dem på et lukket dokument giver dig nul eller et tomt resultat uden undtagelse
Én ting at huske på: Attachment[Index] allokerer og returnerer hele filindholdet ved hver læsning. For et dokument, der bærer et stort indlejret aktiv, betyder det, at du betaler denne allokeringsomkostning ved hvert kald, hvis du itererer gennem alle vedhæftede filer for at bygge en visningsliste. Hvis du kun har brug for navne til visningsformål, skal du læse AttachmentName først og udskyde hentningen af bytes, indtil brugeren rent faktisk anmoder 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;
Udtrækning af en vedhæftet fil til disken
Der findes ingen SaveAttachment-hjælper. Du læser bytes og skriver dem, hvor du har brug for det, hvilket lægger sti-opbygning og sanering helt over på din kode. Det har betydning, når navne på vedhæftede filer kommer fra ikke-betroede dokumenter. PDF-vedhæftningsnavne er strenge, der er gemt inde i filen; de kan indeholde stiseparatorer, Unicode-lookalikes og andre tegn, der vil give uventede resultater, hvis du sender dem direkte til TFileStream.Create. Lad altid navnet passere ExtractFileName, før du bygger en outputsti, og overvej at afvise navne, der starter med et punktum eller indeholder tegn uden for, hvad dit system forventer
Byte-arrayet returneret af Attachment[Index] ejes af kalderen. Skriv det ud med en normal TFileStream, og det er dit til fri afbenyttelse, herunder til at inspicere de første par bytes for at verificere det faktiske filformat frem for at stole på det erklærede navn
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;
Tilføjelse af vedhæftede filer og to-trins skrivning
Oprettelse af en vedhæftet fil kræver to kald, ikke ét. CreateAttachment(Name) registrerer en ny plads i det indlejrede filtræ og returnerer True ved succes. Pladsen starter tom. Derefter tildeler du indholdspakken ved at skrive to Attachment[AttachmentCount - 1], rettet mod den senest oprettede post. Hvis CreateAttachment returnerer False, blev pladsen ikke oprettet, og tildelingen ville beskadige den vedhæftede fil på det indeks, der tilfældigvis er det sidste
Efter ændring af listen over vedhæftede filer lever ændringerne kun i hukommelsen. Kald SaveAs for at skrive en ny fil med det opdaterede indlejrede filtræ. PDFium Component understøtter i øjeblikket ikke lagring tilbage til den samme fil, der er åben, fordi motoren har et læsehåndtag til kilden. Standardmønsteret for en opdatering på stedet er to gemme på en midlertidig sti, lukke dokumentet, slette eller omdøbe originalen, og derefter omdøbe den midlertidige fil på plads og genåbne
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;
Typeoplysninger for vedhæftede filer
Ud over navn og byte-indhold returnerer AttachmentType[Index] MIME-typestrengen gemt i PDF'ens indlejrede filordbog, hvis en sådan blev registreret, da filen oprindeligt blev vedhæftet. Mange generatorer efterlader dette felt tomt eller sætter det til en generisk værdi som application/octet-stream, så du kan ikke stole på det til formatregistrering i en produktions-pipeline. For pålidelig identifikation skal du læse de første par bytes af indholdet og søge efter kendte filsignaturer: %PDF for en indlejret PDF, ZIP-lokalfil-headeren PK\x03\x04 for Office Open XML-dokumenter, \xD0\xCF\x11\xE0 for ældre sammensatte binære filer (compound files). Typeoplysninger fra ordbogen er fine at præsentere i en UI-label, men bør ikke drive behandlingsbeslutninger, når du har de faktiske bytes til rådighed
Sletning af vedhæftede filer
DeleteAttachment(Index) fjerner posten på denne position og returnerer True ved succes. Efter sletning rykker de resterende poster ned, så hvis du sletter flere vedhæftede filer i en løkke, skal du iterere fra det sidste indeks og nedad, ikke fremad, for at undgå at springe poster over efter hvert skift. Ændringen er i hukommelsen, indtil du kalder SaveAs
Et almindeligt scenarie i dokumentbehandlings-pipelines er at fjerne alle vedhæftede filer fra en indgående PDF, før den sendes videre, af hensyn til sikkerhed eller størrelse. Tæl én gang før løkken og iterer baglæns:
procedure StripAllAttachments(Pdf: TPdf);
var
I: Integer;
begin
for I := Pdf.AttachmentCount - 1 downto 0 do
Pdf.DeleteAttachment(I);
end;
Hvor PDF-vedhæftninger optræder i praksis
Attachment-API'en virker på enhver PDF, som PDFium kan åbne, men de dokumenter, hvor du rent faktisk støder på indlejrede filer, samler sig om nogle få specifikke tilfælde. PDF/A-3 (ISO 19005-3) tillader udtrykkeligt overensstemmende indlejrede filer som en mekanisme til at pakke kildedata sammen med arkiveringsversionen; ZUGFeRD- og Factur-X-elektroniske fakturaer er netop afhængige af dette for at indlejre en struktureret XML-indholdspakke i det menneskeligt læsbare PDF-layout. PDF-filer afledt af e-mails bærer nogle gange deres originale e-mail-vedhæftninger videresendt til det indlejrede filtræ. Teknisk dokumentation, der stammer fra strukturerede forfattersystemer, pakker lejlighedsvis understøttende aktiver på samme måde
Når din applikation behandler indgående PDF-filer udefra, er det værd at kontrollere AttachmentCount som en del af dokumentmodtagelsen af to uafhængige årsager. For det første kan indlejrede filer indeholde data, du ønsker at udtrække og behandle, såsom XML'en i en faktura-PDF. For det andet kan indlejrede filer indeholde vilkårligt eksekverbart indhold, så det har betydning at vide, hvad der er til stede, selv når du aldrig har til hensigt at udtrække det. Ingen af årsagerne kræver, at du gør noget kompliceret: Læs antallet, tjek navnene og beslut, hvad du vil gøre med bytes'ene
De attachment-egenskaber, der er vist her, er en del af PDFium Component til Delphi og C++Builder