Teknisk artikel

Arbeta med PDF-bilagor i Delphi med PDFium Component

· PDF-programmering

PDF-dokument kan innehålla inbäddade filbilagor – en kraftfull funktion för att bunta ihop relaterade filer som kalkylblad, bilder eller stöddokument. Den Bilaga demo visar hur man arbetar med PDF-bilagor med PDFium VCL.

Översikt

Denna demo ger fullständig hantering av bilagor inklusive listning, extrahering, tillägg och radering av filbilagor från PDF-dokument. Det är viktigt för dokumenthanteringssystem som behöver hantera komplexa PDF-filer.

Nyckelfunktioner

  • Lista bilagor – Visa alla inbäddade filer i en PDF
  • Extrahera bilagor – Spara bilagor till disk
  • Lägg till bilagor – Bädda in nya filer i PDF-filer
  • Ta bort bilagor – Ta bort bilagor från PDF-filer
  • Visa detaljer – Se bilagornas namn och storlekar

PDFium DLL-krav

Innan du kör ett PDFium VCL-program, se till att PDFium DLL-filerna är installerade:

  • pdfium32.dll / pdfium64.dll – Standardversioner (~5-6 MB)
  • pdfium32v8.dll / pdfium64v8.dll – Med V8 JavaScript-motor (~23-27 MB)

Installation: Kör PDFiumVCL\DLLs\CopyDlls.bat som administratör för att automatiskt kopiera DLL:erna till Windows systemkataloger.

Lista bilagor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
procedure TFormMain.RefreshAttachmentList;
var
  I: Integer;
  AttachmentName: string;
  AttachmentData: TBytes;
  SizeStr: string;
begin
  ListBoxAttachments.Items.Clear;
  
  if not Pdf.Active then
    Exit;
    
  for I := 0 to Pdf.AttachmentCount - 1 do
  begin
    AttachmentName := Pdf.AttachmentName[I];
    AttachmentData := Pdf.Attachment[I];
    
    // Format size
    if Length(AttachmentData) >= 1024 * 1024 then
      SizeStr := Format('%.2f MB', [Length(AttachmentData) / (1024 * 1024)])
    else if Length(AttachmentData) >= 1024 then
      SizeStr := Format('%.2f KB', [Length(AttachmentData) / 1024])
    else
      SizeStr := Format('%d bytes', [Length(AttachmentData)]);
      
    ListBoxAttachments.Items.Add(Format('%s (%s)', [AttachmentName, SizeStr]));
  end;
  
  LogStatus(Format('Found %d attachment(s)', [Pdf.AttachmentCount]));
end;

Extrahera bilagor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
procedure TFormMain.ButtonExtractAttachmentClick(Sender: TObject);
var
  Index: Integer;
  AttachmentName: string;
  AttachmentData: TBytes;
  FileStream: TFileStream;
begin
  Index := GetSelectedAttachmentIndex;
  if Index < 0 then
  begin
    LogStatus('Please select an attachment to extract.');
    Exit;
  end;
  
  try
    AttachmentName := Pdf.AttachmentName[Index];
    AttachmentData := Pdf.Attachment[Index];
    
    SaveDialog.FileName := AttachmentName;
    if SaveDialog.Execute then
    begin
      FileStream := TFileStream.Create(SaveDialog.FileName, fmCreate);
      try
        if Length(AttachmentData) > 0 then
          FileStream.WriteBuffer(AttachmentData[0], Length(AttachmentData));
          
        LogStatus('Extracted: ' + SaveDialog.FileName);
      finally
        FileStream.Free;
      end;
    end;
    
  except
    on E: Exception do
      LogStatus('Error extracting attachment: ' + E.Message);
  end;
end;

Lägger till bilagor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
procedure TFormMain.ButtonAddAttachmentClick(Sender: TObject);
var
  AttachmentName: string;
  FileData: TBytes;
  FileStream: TFileStream;
begin
  if not Pdf.Active then
  begin
    LogStatus('Please load or create a PDF document first.');
    Exit;
  end;
  
  OpenDialog.Filter := 'All Files|*.*';
  if OpenDialog.Execute then
  begin
    try
      // Read file into byte array
      FileStream := TFileStream.Create(OpenDialog.FileName, fmOpenRead);
      try
        SetLength(FileData, FileStream.Size);
        if FileStream.Size > 0 then
          FileStream.ReadBuffer(FileData[0], FileStream.Size);
      finally
        FileStream.Free;
      end;
      
      // Use filename as attachment name
      AttachmentName := ExtractFileName(OpenDialog.FileName);
      
      // Create attachment slot
      if Pdf.CreateAttachment(AttachmentName) then
      begin
        // Find the new attachment and set its data
        Pdf.Attachment[Pdf.AttachmentCount - 1] := FileData;
        
        LogStatus('Added attachment: ' + AttachmentName);
        RefreshAttachmentList;
      end
      else
        LogStatus('Failed to create attachment: ' + AttachmentName);
        
    except
      on E: Exception do
        LogStatus('Error adding attachment: ' + E.Message);
    end;
  end;
end;

Ta bort bilagor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
procedure TFormMain.ButtonDeleteAttachmentClick(Sender: TObject);
var
  Index: Integer;
  AttachmentName: string;
begin
  Index := GetSelectedAttachmentIndex;
  if Index < 0 then
  begin
    LogStatus('Please select an attachment to delete.');
    Exit;
  end;
  
  try
    AttachmentName := Pdf.AttachmentName[Index];
    
    if MessageDlg(Format('Delete attachment "%s"?', [AttachmentName]),
      mtConfirmation, [mbYes, mbNo], 0) = mrYes then
    begin
      if Pdf.DeleteAttachment(Index) then
      begin
        LogStatus('Deleted attachment: ' + AttachmentName);
        RefreshAttachmentList;
      end
      else
        LogStatus('Failed to delete attachment.');
    end;
    
  except
    on E: Exception do
      LogStatus('Error deleting attachment: ' + E.Message);
  end;
end;

Åtkomst till bifogade egenskaper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Number of attachments
Count := Pdf.AttachmentCount;
 
// Attachment name at index
Name := Pdf.AttachmentName[Index];
 
// Attachment data as byte array
Data := Pdf.Attachment[Index];
 
// Set attachment data
Pdf.Attachment[Index] := NewData;
 
// Create new attachment
Success := Pdf.CreateAttachment('filename.txt');
 
// Delete attachment
Success := Pdf.DeleteAttachment(Index);

Skapa ett nytt dokument med bilagor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
procedure CreatePdfWithAttachments;
var
  Pdf: TPdf;
  FileData: TBytes;
  FileStream: TFileStream;
begin
  Pdf := TPdf.Create(nil);
  try
    // Create new document
    Pdf.CreateDocument;
    Pdf.Active := True;
    
    // Add a page
    Pdf.AddPage(1, 595, 842);
    Pdf.PageNumber := 1;
    Pdf.AddText('Document with Attachments', 'Arial', 18, 50, 750,
      clBlack, $FF, 0.0);
    
    // Add first attachment
    FileStream := TFileStream.Create('data.csv', fmOpenRead);
    try
      SetLength(FileData, FileStream.Size);
      FileStream.ReadBuffer(FileData[0], FileStream.Size);
    finally
      FileStream.Free;
    end;
    
    if Pdf.CreateAttachment('data.csv') then
      Pdf.Attachment[0] := FileData;
      
    // Add second attachment
    FileStream := TFileStream.Create('readme.txt', fmOpenRead);
    try
      SetLength(FileData, FileStream.Size);
      FileStream.ReadBuffer(FileData[0], FileStream.Size);
    finally
      FileStream.Free;
    end;
    
    if Pdf.CreateAttachment('readme.txt') then
      Pdf.Attachment[1] := FileData;
      
    // Save
    Pdf.SaveAs('document_with_attachments.pdf');
    
  finally
    Pdf.Active := False;
    Pdf.Free;
  end;
end;

Spara dokument efter ändringar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
procedure TFormMain.ButtonSaveDocumentClick(Sender: TObject);
var
  CurrentFileName, TempFileName: string;
  WasActive: Boolean;
begin
  SaveDialog.Filter := 'PDF Files|*.pdf|All Files|*.*';
  SaveDialog.DefaultExt := 'pdf';
  
  if SaveDialog.Execute then
  begin
    try
      CurrentFileName := Pdf.FileName;
      WasActive := Pdf.Active;
      
      // If saving to the same file, use temporary file
      if WasActive and SameText(CurrentFileName, SaveDialog.FileName) then
      begin
        TempFileName := SaveDialog.FileName + '.tmp';
        
        if Pdf.SaveAs(TempFileName) then
        begin
          // Close, delete old, rename new
          Pdf.Active := False;
          
          if DeleteFile(CurrentFileName) then
          begin
            if RenameFile(TempFileName, SaveDialog.FileName) then
            begin
              // Reload
              Pdf.FileName := SaveDialog.FileName;
              Pdf.Active := True;
              LogStatus('Document saved successfully.');
            end;
          end;
        end;
      end
      else
      begin
        // Save to different file
        if Pdf.SaveAs(SaveDialog.FileName) then
          LogStatus('Document saved: ' + ExtractFileName(SaveDialog.FileName))
        else
          LogStatus('Failed to save document.');
      end;
      
    except
      on E: Exception do
        LogStatus('Error saving document: ' + E.Message);
    end;
  end;
end;

Visar bilagadetaljer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
procedure TFormMain.ListBoxAttachmentsClick(Sender: TObject);
var
  Index: Integer;
  AttachmentName: string;
  AttachmentData: TBytes;
begin
  Index := GetSelectedAttachmentIndex;
  
  if Index >= 0 then
  begin
    AttachmentName := Pdf.AttachmentName[Index];
    AttachmentData := Pdf.Attachment[Index];
    
    MemoDetails.Lines.Clear;
    MemoDetails.Lines.Add('Name: ' + AttachmentName);
    MemoDetails.Lines.Add('Size: ' + IntToStr(Length(AttachmentData)) + ' bytes');
    MemoDetails.Lines.Add('Index: ' + IntToStr(Index));
    
    // Try to detect file type from extension
    if EndsText('.txt', AttachmentName) or
       EndsText('.csv', AttachmentName) then
      MemoDetails.Lines.Add('Type: Text file')
    else if EndsText('.pdf', AttachmentName) then
      MemoDetails.Lines.Add('Type: PDF document')
    else if EndsText('.jpg', AttachmentName) or
            EndsText('.png', AttachmentName) then
      MemoDetails.Lines.Add('Type: Image file')
    else
      MemoDetails.Lines.Add('Type: Binary file');
  end;
end;

Användningsfall

  • Dokumentpaket – Bunta huvuddokument med stödfiler
  • Formulärinlämningar – Bifoga bevis eller styrkande handlingar till formulär
  • Tekniska manualer – Inkludera CAD-filer, kalkylblad eller källkod
  • Juridiska dokument – Bifoga utställningar och bilagor
  • Arkivhantering – Extrahera bilagor för bearbetning

Slutsats

Bilagademon visar hur PDFium VCL ger fullständig kontroll över PDF-filbilagor. Oavsett om du bygger ett dokumenthanteringssystem eller bearbetar PDF-formulär med inbäddade filer, gör dessa API:er det enkelt.

Möjligheten att lägga till, extrahera och ta bort bilagor programmässigt öppnar många möjligheter för dokumentautomatisering och bearbetningsarbetsflöden.

Hantera PDF-bilagor med enkel användning Delphi PDFium VCL.