PDF-bestandsbijlagen worden opgeslagen in de boomstructuur van ingebedde bestanden (embedded-file tree) van het document, een structuur die de meeste viewers tonen als een paneel met een paperclip of een zijbalk met bijlagen. Vanuit Delphi-code stelt PDFium Component die boomstructuur bloot via een kleine set geïndexeerde eigenschappen op TPdf: u doorloopt deze met een integer-index, leest namen en byte-payloads, maakt nieuwe posities aan en verwijdert bestaande. De API is compact; er zijn slechts een paar volgordebeperkingen en één opschoningsregel voor paden die u moet kennen voordat u hieromheen productiecode schrijft
Bijlagen lezen uit een geopend document
AttachmentCount geeft het aantal ingebedde bestanden aan dat het document declareert. Het leest rechtstreeks uit de onderliggende aanroep van PDFium, dus het weerspiegelt alleen wat de PDF daadwerkelijk bevat. Van daaruit retourneert AttachmentName[Index] de weergavenaam als een WString, en levert Attachment[Index] de ruwe bytes als een TBytes-array. Beide zijn zero-based. Het document moet geopend zijn (Pdf.Active = True) voordat u een van beide eigenschappen opvraagt; als u ze aanroept op een gesloten document, krijgt u nul of een leeg resultaat zonder uitzondering
Eén ding om in gedachten te houden: Attachment[Index] alloceert en retourneert de volledige bestandsinhoud bij elke leesbewerking. Voor een document met een groot ingebed bestand betekent het doorlopen van alle bijlagen om een weergavelijst op te bouwen, dat u die allocatiekosten bij elke aanroep betaalt. Als u alleen namen nodig hebt voor weergavedoeleinden, lees dan eerst AttachmentName en stel het ophalen van de bytes uit totdat de gebruiker daadwerkelijk om het bestand vraagt
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;
Een bijlage naar schijf exporteren
Er is geen SaveAttachment-hulpmiddel. U leest de bytes en schrijft ze waar u ze nodig hebt, waardoor padconstructie en opschoning volledig aan uw code worden overgelaten. Dat is belangrijk wanneer bijlagnamen afkomstig zijn van niet-vertrouwde documenten. Namen van PDF-bijlagen zijn strings die in het bestand zijn opgeslagen; ze kunnen padscheidingstekens, Unicode-lookalikes en andere karakters bevatten die onverwachte resultaten opleveren als u ze rechtstreeks doorgeeft aan TFileStream.Create. Voer de naam altijd uit via ExtractFileName voordat u een uitvoerpad bouwt, en overweeg om namen te weigeren die beginnen met een punt of karakters bevatten die buiten de verwachtingen van uw systeem vallen
De byte-array die wordt geretourneerd door Attachment[Index] is eigendom van de aanroeper. Schrijf deze weg met een normale TFileStream en u kunt ermee doen wat u wilt, inclusief het inspecteren van de eerste paar bytes om het daadwerkelijke bestandsformaat te verifiëren in plaats van de gedeclareerde naam te vertrouwen
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;
Bijlagen toevoegen en het schrijven in twee stappen
Het maken van een bijlage vereist twee aanroepen, niet één. CreateAttachment(Name) registreert een nieuwe positie in de boomstructuur van ingebedde bestanden en retourneert True bij succes. Die positie begint leeg. Vervolgens wijst u de payload toe door te schrijven naar Attachment[AttachmentCount - 1], gericht op de meest recent gemaakte vermelding. Als CreateAttachment False retourneert, is de positie niet aangemaakt en zou de toewijzing de bijlage op de index die toevallig de laatste is, beschadigen
Na het wijzigen van de bijlagenlijst zijn de wijzigingen alleen in het geheugen aanwezig. Roep SaveAs aan om een nieuw bestand te schrijven met de bijgewerkte boomstructuur van ingebedde bestanden. PDFium Component ondersteunt momenteel geen opslag in hetzelfde bestand dat momenteel geopend is, omdat de engine een lees-handgreep (read handle) naar de bron vasthoudt. Het standaardpatroon voor een in-place update is om op te slaan naar een tijdelijk pad, het document te sluiten, het origineel te verwijderen of te hernoemen, en vervolgens het tijdelijke bestand naar de juiste positie te hernoemen en opnieuw te openen
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;
Type-informatie van bijlagen
Naast de naam en byte-payload retourneert AttachmentType[Index] de MIME-type-string die is opgeslagen in het woordenboek van het ingebedde bestand in de PDF, als er een is vastgelegd toen het bestand oorspronkelijk werd bijgevoegd. Veel generatoren laten dit veld leeg of stellen het in op een generieke waarde zoals application/octet-stream, dus u kunt hier in een productiepijplijn niet op vertrouwen voor formaatdetectie. Lees voor een betrouwbare identificatie de eerste paar bytes van de payload en controleer op bekende bestandssignaturen: %PDF voor een geneste PDF, de lokale ZIP-bestandsheader PK\x03\x04 voor Office Open XML-documenten, \xD0\xCF\x11\xE0 voor oudere binaire bestanden (compound files). Type-informatie uit het woordenboek kan prima in een UI-label worden getoond, maar mag geen verwerkingsbeslissingen sturen wanneer u de werkelijke bytes beschikbaar hebt
Bijlagen verwijderen
DeleteAttachment(Index) verwijdert de vermelding op die positie en retourneert True bij succes. Na verwijdering verschuiven de overige vermeldingen naar beneden. Als u meerdere bijlagen in een lus verwijdert, moet u dus van de laatste index naar beneden lopen, en niet vooruit, om te voorkomen dat u vermeldingen overslaat na elke verschuiving. De wijziging is in het geheugen totdat u SaveAs aanroept
Een veelvoorkomend scenario in documentverwerkingspijplijnen is het verwijderen van alle bijlagen uit een binnenkomende PDF voordat deze downstream wordt doorgestuurd, om veiligheids- of grootteredenen. Tel eenmaal voor de lus en doorloop deze in omgekeerde volgorde:
procedure StripAllAttachments(Pdf: TPdf);
var
I: Integer;
begin
for I := Pdf.AttachmentCount - 1 downto 0 do
Pdf.DeleteAttachment(I);
end;
Waar PDF-bijlagen in de praktijk voorkomen
De bijlagen-API werkt op elke PDF die PDFium kan openen, maar de documenten waarin u daadwerkelijk ingebedde bestanden tegenkomt, concentreren zich rond een paar specifieke gevallen. PDF/A-3 (ISO 19005-3) staat expliciet ingebedde bestanden toe die voldoen aan de specificaties als mechanisme voor het bundelen van brongegevens naast de archiefweergave; ZUGFeRD- en Factur-X elektronische facturen vertrouwen op exact dit mechanisme om een gestructureerde XML-payload in te bedden in de menselijk leesbare PDF-lay-out. Van e-mail afgeleide PDF's dragen soms hun originele berichtbijlagen doorgegeven aan de boomstructuur van ingebedde bestanden. Technische documentatie die afkomstig is uit gestructureerde auteurssystemen bundelt ondersteunende middelen soms op dezelfde manier
Wanneer uw applicatie inkomende PDF's van buiten uw organisatie verwerkt, is het controleren van AttachmentCount als onderdeel van de documentinname om twee onafhankelijke redenen de moeite waard. Ten eerste kunnen ingebedde bestanden gegevens bevatten die u wilt extraheren en verwerken, zoals de XML in een factuur-PDF. Ten tweede kunnen ingebedde bestanden willekeurige uitvoerbare inhoud bevatten, dus weten wat er aanwezig is is belangrijk, zelfs als u nooit van plan bent het te extraheren. Geen van beide redenen vereist ingewikkelde acties: lees het aantal, controleer de namen en beslis wat u met de bytes doet
De bijlagen-eigenschappen die hier worden getoond, maken deel uit van het PDFium Component voor Delphi en C++Builder