技术文章

在 Delphi 中使用 PDFium VCL 将图像转换为 PDF 文档

· PDF 编程

将图像转换为PDF是一种常见的需求,用于文档管理、归档和共享。 图像转PDF 该演示程序展示了如何使用PDFium VCL从一组图像创建多页PDF文档。

概述

此演示程序允许用户选择多个图像,预览它们,如果需要可以重新排序,并将它们转换为单个PDF文档。每个图像都将成为PDF中的一页,并进行适当的缩放和居中。

主要特性

  • 多图像支持 – 一次添加多个图像
  • 格式支持 – 支持JPEG、PNG、BMP、GIF和TIFF图像。
  • 图像预览 – 在转换前预览图像
  • 自动页面大小 – 根据图像方向选择纵向或横向
  • 智能缩放 – 图像按比例缩放以适应页面,并留有边距
  • 图像信息 – 在每页上显示原始大小和缩放比例因子

PDFium DLL 的要求

在运行任何 PDFium VCL 应用程序之前,请确保已安装 PDFium DLL 文件:

  • pdfium32.dll / pdfium64.dll – 标准版本(约 5-6 MB)
  • pdfium32v8.dll / pdfium64v8.dll – 包含 V8 JavaScript 引擎的版本(约 23-27 MB)

安装: 运行 PDFiumVCL\DLLs\CopyDlls.bat 以管理员身份,自动将 DLL 文件复制到 Windows 系统目录。

从图像创建 PDF。

核心转换过程:

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
procedure TFormMain.CreatePDFFromImages;
var
  I: Integer;
  PageWidth, PageHeight: Double;
  ImageWidth, ImageHeight: Double;
  ScaleX, ScaleY, Scale: Double;
  ImageSize: TSize;
  X, Y: Double;
  Picture: TPicture;
begin
  if FImageList.Count = 0 then
    Exit;
    
  ProgressBar.Visible := True;
  ProgressBar.Max := FImageList.Count;
  ProgressBar.Position := 0;
  
  try
    // Create new PDF document
    Pdf.CreateDocument;
    Pdf.Active := True;
    
    for I := 0 to FImageList.Count - 1 do
    begin
      try
        // Load the image
        Picture := TPicture.Create;
        try
          Picture.LoadFromFile(FImageList[I]);
          
          // Get image dimensions
          ImageSize.cx := Picture.Width;
          ImageSize.cy := Picture.Height;
          
          // Set page orientation based on image
          if ImageSize.cx > ImageSize.cy then
          begin
            // Landscape
            PageWidth := 842;  // A4 landscape
            PageHeight := 595;
          end
          else
          begin
            // Portrait
            PageWidth := 595;  // A4 portrait
            PageHeight := 842;
          end;
          
          // Create page
          Pdf.AddPage(I + 1, PageWidth, PageHeight);
          Pdf.PageNumber := I + 1;
          
          // Calculate scaling
          ImageWidth := ImageSize.cx;
          ImageHeight := ImageSize.cy;
          
          ScaleX := (PageWidth - 80) / ImageWidth;   // 40pt margin each side
          ScaleY := (PageHeight - 120) / ImageHeight; // 40pt + space for text
          Scale := Min(ScaleX, ScaleY);
          
          ImageWidth := ImageWidth * Scale;
          ImageHeight := ImageHeight * Scale;
          
          // Center on page
          X := (PageWidth - ImageWidth) / 2;
          Y := (PageHeight - ImageHeight) / 2;
          
          // Add image to PDF
          Pdf.AddPicture(Picture, X, Y, ImageWidth, ImageHeight);
          
          // Add image information
          Pdf.AddText(Format('File: %s', [ExtractFileName(FImageList[I])]),
            'Arial', 10, X, Y + ImageHeight + 10, clBlack, $FF, 0.0);
          Pdf.AddText(Format('Original: %dx%d px, Scale: %.1f%%',
            [ImageSize.cx, ImageSize.cy, Scale * 100]),
            'Arial', 8, X, Y + ImageHeight + 25, clGray, $FF, 0.0);
            
        finally
          Picture.Free;
        end;
        
        ProgressBar.Position := I + 1;
        Application.ProcessMessages;
        
      except
        on E: Exception do
          // Continue with next image on error
          LabelStatus.Caption := 'Error: ' + E.Message;
      end;
    end;
    
    // Save the PDF
    Pdf.SaveAs(SaveDialog.FileName);
    ShowMessage(Format('PDF created with %d pages!', [FImageList.Count]));
    
  finally
    ProgressBar.Visible := False;
    Pdf.Active := False;
  end;
end;

将图像添加到列表中。

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
procedure TFormMain.BtnAddImagesClick(Sender: TObject);
var
  I: Integer;
  ListItem: TListItem;
  FileSize: Int64;
  FileSizeStr: string;
begin
  if OpenPictureDialog.Execute then
  begin
    for I := 0 to OpenPictureDialog.Files.Count - 1 do
    begin
      FImageList.Add(OpenPictureDialog.Files[I]);
      
      // Add to ListView
      ListItem := ListView.Items.Add;
      ListItem.Caption := ExtractFileName(OpenPictureDialog.Files[I]);
      ListItem.SubItems.Add(OpenPictureDialog.Files[I]); // Full path
      
      // Get file size
      try
        FileSize := GetFileSizeHelper(OpenPictureDialog.Files[I]);
        if FileSize >= 1024 * 1024 then
          FileSizeStr := Format('%.1f MB', [FileSize / (1024 * 1024)])
        else if FileSize >= 1024 then
          FileSizeStr := Format('%.1f KB', [FileSize / 1024])
        else
          FileSizeStr := Format('%d bytes', [FileSize]);
      except
        FileSizeStr := 'Unknown';
      end;
      ListItem.SubItems.Add(FileSizeStr);
    end;
    
    UpdateUI;
    LabelStatus.Caption := Format('Added %d image(s). Total: %d images',
      [OpenPictureDialog.Files.Count, FImageList.Count]);
  end;
end;

使用 AddPicture 方法。

好的。 AddPicture 该方法接受一个 TPicture 对象,该对象支持各种图像格式:

1
2
3
4
5
// Add picture with automatic sizing
procedure TPdf.AddPicture(Picture: TPicture; X, Y: Double);
 
// Add picture with specific size
procedure TPdf.AddPicture(Picture: TPicture; X, Y, Width, Height: Double);

直接添加 JPEG 图像。

对于 JPEG 图像,可以使用优化的。 AddJpegImage 方法:

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
function AddJpegFromFile(const FileName: string): Boolean;
var
  Pdf: TPdf;
  FileStream: TFileStream;
begin
  Pdf := TPdf.Create(nil);
  try
    Pdf.CreateDocument;
    Pdf.Active := True;
    Pdf.AddPage(1, 595, 842);
    Pdf.PageNumber := 1;
    
    FileStream := TFileStream.Create(FileName, fmOpenRead);
    try
      // Add JPEG directly - more efficient than loading as TPicture
      Result := Pdf.AddJpegImage(FileStream, 50, 50, 495, 742);
    finally
      FileStream.Free;
    end;
    
    Pdf.SaveAs('output.pdf');
    
  finally
    Pdf.Active := False;
    Pdf.Free;
  end;
end;

预览选定的图像

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
procedure TFormMain.ListViewSelectItem(Sender: TObject; Item: TListItem;
  Selected: Boolean);
begin
  if Selected and (Item <> nil) then
  begin
    LoadImagePreview(Item.SubItems[0]); // Full path
  end;
end;
 
procedure TFormMain.LoadImagePreview(const FileName: string);
begin
  try
    if FileExists(FileName) then
    begin
      ImagePreview.Picture.LoadFromFile(FileName);
      ImagePreview.Proportional := True;
      ImagePreview.Stretch := True;
      LabelStatus.Caption := 'Preview: ' + ExtractFileName(FileName);
    end;
  except
    on E: Exception do
    begin
      ImagePreview.Picture.Assign(nil);
      LabelStatus.Caption := 'Error loading preview: ' + E.Message;
    end;
  end;
end;

删除和重新排序图像

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
procedure TFormMain.BtnRemoveSelectedClick(Sender: TObject);
var
  I, RemovedCount: Integer;
begin
  RemovedCount := 0;
  
  if ListView.SelCount > 0 then
  begin
    // Remove from back to front to avoid index issues
    for I := ListView.Items.Count - 1 downto 0 do
    begin
      if ListView.Items[I].Selected then
      begin
        FImageList.Delete(I);
        ListView.Items.Delete(I);
        Inc(RemovedCount);
      end;
    end;
    
    if (FImageList.Count = 0) or (ListView.Selected = nil) then
      ImagePreview.Picture.Assign(nil);
      
    UpdateUI;
    LabelStatus.Caption := Format('Removed %d item(s). Total: %d images',
      [RemovedCount, FImageList.Count]);
  end;
end;

设置对话框

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
procedure TFormMain.FormCreate(Sender: TObject);
begin
  FImageList := TStringList.Create;
  
  // Setup ListView
  ListView.ViewStyle := vsReport;
  ListView.Columns.Add.Caption := 'File Name';
  ListView.Columns.Add.Caption := 'Path';
  ListView.Columns.Add.Caption := 'Size';
  ListView.Columns[0].Width := 200;
  ListView.Columns[1].Width := 300;
  ListView.Columns[2].Width := 100;
  ListView.RowSelect := True;
  ListView.MultiSelect := True;
  
  // Setup dialogs
  OpenPictureDialog.Filter :=
    'Image Files|*.jpg;*.jpeg;*.png;*.bmp;*.gif;*.tiff;*.tif|' +
    'JPEG Files|*.jpg;*.jpeg|' +
    'PNG Files|*.png|' +
    'Bitmap Files|*.bmp|' +
    'All Files|*.*';
  OpenPictureDialog.Options := [ofAllowMultiSelect, ofPathMustExist, ofFileMustExist];
  
  SaveDialog.Filter := 'PDF Files|*.pdf|All Files|*.*';
  SaveDialog.DefaultExt := 'pdf';
  
  UpdateUI;
end;

用例

  • 相册 – 从数字照片创建 PDF 相册
  • 文档扫描 – 将扫描的页面图像合并为单个 PDF
  • 制作作品集 将艺术作品图像转换为 PDF 格式的文档。
  • 归档。 将图像集合转换为 PDF 格式,用于长期存储。
  • 报告生成 在 PDF 报告中包含截图和图表。

结论。

Image to PDF 演示版展示了 PDFium VCL 如何轻松创建专业的 PDF 文档,它具有自动页面大小调整、智能缩放以及对多种图像格式的支持,可用于构建强大的图像到 PDF 转换工具。

好的。 AddPicture 该方法处理将图像嵌入到 PDF 页面中的复杂性,而您则专注于应用程序的用户界面和工作流程。

试用 PDFium VCL 组件。 从 loslab.com 开始,立即创建 PDF 文档。