技术文章

在 Delphi 中使用 PDFium VCL 分析 PDF 字体属性

· PDF 编程

了解 PDF 文档中使用的字体对于质量控制、可访问性合规性和文档取证至关重要。 字体属性 该演示程序展示了如何使用 PDFium VCL 访问 PDF 中字符的详细字体信息。

概述

此演示程序允许您单击 PDF 中的任何字符,并查看其字体属性,包括字体名称、粗细、样式、大小以及字体是否嵌入。它对于 PDF 分析和故障排除非常有价值。

主要特性

  • 交互式选择 – 单击任何字符以进行分析
  • 字体名称 – 字体系列(例如,“Arial”、“Times New Roman”)
  • 字体基础名称 – 内部 PDF 字体名称
  • 字体粗细 – 数值粗细 (400 = normal, 700 = bold)
  • 字体大小 – 以点为单位的大小
  • 倾斜角度 – 倾斜字体的大小角度
  • 上升/下降 – 垂直指标
  • 嵌入状态 – 是否将字体嵌入到 PDF 中
  • 字体数据 – 如果已嵌入,则访问原始字体数据

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 系统目录。

访问字体属性

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
procedure TfrmMain.UpdateFontInfo;
var
  FontInfo: TStringList;
begin
  FontInfo := TStringList.Create;
  try
    FontInfo.Add('=== Font Properties for Character Index: ' +
      IntToStr(PdfView.CurrentCharIndex) + ' ===');
    FontInfo.Add('');
    
    // Font family name
    try
      FontInfo.Add('Font Family Name: ' + PdfView.FontFamilyName);
    except
      FontInfo.Add('Font Family Name: \u003cError retrieving\u003e');
    end;
    
    // Font base name (internal PDF name)
    try
      FontInfo.Add('Font Base Name: ' + PdfView.FontBaseName);
    except
      FontInfo.Add('Font Base Name: \u003cError retrieving\u003e');
    end;
    
    // Font size for this character
    try
      FontInfo.Add('Font Size: ' +
        FloatToStr(PdfView.FontSize[PdfView.CurrentCharIndex]));
    except
      FontInfo.Add('Font Size: \u003cError retrieving\u003e');
    end;
    
    // Font weight (400=normal, 700=bold)
    try
      FontInfo.Add('Font Weight: ' + IntToStr(PdfView.FontWeight));
    except
      FontInfo.Add('Font Weight: \u003cError retrieving\u003e');
    end;
    
    // Italic angle (0 for upright, negative for italic)
    try
      FontInfo.Add('Font Italic Angle: ' + IntToStr(PdfView.FontItalicAngle));
    except
      FontInfo.Add('Font Italic Angle: \u003cError retrieving\u003e');
    end;
    
    // Vertical metrics
    try
      FontInfo.Add('Font Ascent: ' + FloatToStr(PdfView.FontAscent));
    except
      FontInfo.Add('Font Ascent: \u003cError retrieving\u003e');
    end;
    
    try
      FontInfo.Add('Font Descent: ' + FloatToStr(PdfView.FontDescent));
    except
      FontInfo.Add('Font Descent: \u003cError retrieving\u003e');
    end;
    
    // Embedded status
    try
      FontInfo.Add('Font Is Embedded: ' +
        BoolToStr(PdfView.FontIsEmbedded, True));
    except
      FontInfo.Add('Font Is Embedded: \u003cError retrieving\u003e');
    end;
    
    // Font data size (if embedded)
    try
      FontInfo.Add('Font Data Size: ' +
        IntToStr(Length(PdfView.FontData)) + ' bytes');
    except
      FontInfo.Add('Font Data Size: \u003cError retrieving\u003e');
    end;
    
    FontInfo.Add('');
    FontInfo.Add('Character: ' +
      PdfView.Character[PdfView.CurrentCharIndex]);
    
    memoFontInfo.Lines.Assign(FontInfo);
    
  finally
    FontInfo.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 TfrmMain.PdfViewMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  CharIndex: Integer;
begin
  if not PdfView.Active then
    Exit;
    
  try
    // Get character at click position
    CharIndex := PdfView.CharacterIndexAtPos(X, Y, 10.0, 10.0);
    
    if CharIndex >= 0 then
    begin
      edtCharIndex.Text := IntToStr(CharIndex);
      PdfView.CurrentCharIndex := CharIndex;
      UpdateFontInfo;
    end;
    
  except
    on E: Exception do
    begin
      memoFontInfo.Lines.Clear;
      memoFontInfo.Lines.Add('Error getting character: ' + E.Message);
    end;
  end;
end;

手动字符索引输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
procedure TfrmMain.btnGetFontInfoClick(Sender: TObject);
var
  CharIndex: Integer;
begin
  if not PdfView.Active then
  begin
    ShowMessage('Please open a PDF file first.');
    Exit;
  end;
  
  try
    CharIndex := StrToInt(edtCharIndex.Text);
    PdfView.CurrentCharIndex := CharIndex;
    UpdateFontInfo;
  except
    on E: Exception do
      ShowMessage('Invalid character index: ' + E.Message);
  end;
end;

可用的字体属性

PDFium VCL 暴露了以下与字体相关的属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
// Font properties accessible via TPdf and TPdfView
property FontFamilyName: WString;  // e.g., "Arial", "Times New Roman"
property FontBaseName: WString;    // Internal PDF font name
property FontWeight: Integer;      // 100-900, 400=normal, 700=bold
property FontItalicAngle: Integer; // Degrees, 0=upright, negative=italic
property FontAscent: Single;       // Height above baseline
property FontDescent: Single;      // Depth below baseline (negative)
property FontIsEmbedded: Boolean;  // True if font is embedded
property FontData: TBytes;         // Raw font data if embedded
property FontHandle: FPDF_FONT;    // PDFium font handle
 
// Per-character property
property FontSize[Index: Integer]: Double;  // Font size for character

使用字体属性进行分析

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 AnalyzeDocumentFonts(Pdf: TPdf);
var
  FontList: TStringList;
  I: Integer;
  FontName: string;
  LastFontName: string;
begin
  FontList := TStringList.Create;
  FontList.Sorted := True;
  FontList.Duplicates := dupIgnore;
  
  try
    Pdf.PageNumber := 1;
    LastFontName := '';
    
    for I := 0 to Pdf.CharacterCount - 1 do
    begin
      // Access font for each character
      // (In practice, use CurrentCharIndex pattern)
      
      // Check FontFamilyName changes
      // Add unique fonts to list
    end;
    
    ShowMessage('Document uses ' + IntToStr(FontList.Count) + ' fonts');
    
  finally
    FontList.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
28
29
30
31
32
procedure CheckFontEmbedding(Pdf: TPdf);
var
  EmbeddedFonts, NonEmbeddedFonts: TStringList;
begin
  EmbeddedFonts := TStringList.Create;
  NonEmbeddedFonts := TStringList.Create;
  
  try
    EmbeddedFonts.Sorted := True;
    EmbeddedFonts.Duplicates := dupIgnore;
    NonEmbeddedFonts.Sorted := True;
    NonEmbeddedFonts.Duplicates := dupIgnore;
    
    // Analyze fonts...
    
    if NonEmbeddedFonts.Count > 0 then
    begin
      ShowMessage('Warning: ' + IntToStr(NonEmbeddedFonts.Count) +
        ' fonts are not embedded. Document may not display correctly ' +
        'on systems without these fonts installed.');
    end
    else
    begin
      ShowMessage('All fonts are embedded. Document will display ' +
        'consistently on all systems.');
    end;
    
  finally
    EmbeddedFonts.Free;
    NonEmbeddedFonts.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
procedure ExtractEmbeddedFont(Pdf: TPdf; const OutputFile: string);
var
  FontData: TBytes;
  FileStream: TFileStream;
begin
  if Pdf.FontIsEmbedded then
  begin
    FontData := Pdf.FontData;
    
    if Length(FontData) > 0 then
    begin
      FileStream := TFileStream.Create(OutputFile, fmCreate);
      try
        FileStream.WriteBuffer(FontData[0], Length(FontData));
        ShowMessage('Font extracted: ' + IntToStr(Length(FontData)) + ' bytes');
      finally
        FileStream.Free;
      end;
    end;
  end
  else
    ShowMessage('Font is not embedded in the document.');
end;

理解字体粗细值

Weight Value Common Name
100 Thin
200 Extra Light
300 Light
400 Normal/Regular
500 Medium
600 Semi Bold
700 Bold
800 Extra Bold
900 Black

用例

  • 质量控制 – 验证文档中是否使用了正确的字体
  • 可访问性 – 检查字体是否符合可访问性要求
  • 法医分析 – 分析文档的来源和修改
  • 打印预检 – 在生产前验证字体嵌入
  • 字体库存 – 记录文档中使用的字体

结论。

字体属性演示展示了 PDFium VCL 如何提供对 PDF 文档中字体信息的深入访问。无论您是检查打印生产中的字体嵌入,还是分析文档排版,这些 API 都能为您提供所需的工具。

能够点击任意字符并立即查看其字体属性,使 PDF 分析直观且高效。

深入探索 PDF 字体。 使用 PDFium Delphi VCL 组件。.