首页 / 资讯中心 / 文章详情

Delphi 10.3深度集成PDFium全源码组件套件

Delphi 10.3深度集成PDFium全源码组件套件 ★ FEATURED ARTICLE
简介Winsoft PDFium Component Suite 5.4 是一套面向 Delphi 和 C Builder 开发者的高性能 PDF 处理组件库专为需要在桌面应用中集成 PDF 查看、导航、文本提取与编辑功能的中高级开发者设计。基于 Google 开源 PDFium 渲染引擎兼容 Delphi/C Builder 5 至 10.3 及 Lazarus 2.0.6支持跨版本开发与深度定制。资源包共 1010 个文件涵盖 35 个核心 Pascal 源码.pas、31 个包定义.dpk、23 个设计时组件资源.dcr、44 个 C 头文件.hpp及 7 个 PDFium 引擎相关模块完整提供全部源代码与编译产物.dcu/.bpl/.ppu便于调试、二次开发与静态链接。压缩包大小 23.75MB结构清晰含 Demo 工程.cbproj、帮助文档.chm、许可证文件及详细 README开箱即可构建示例并深入理解 PDFium 封装逻辑。已有 622 人学习下载是 Delphi 生态中少有的全源码、多版本兼容、工业级可用的 PDF 解决方案。1. Delphi 10.3 下真正能编译、调试、二次开发的 PDFium 全源码组件套件不是封装 DLL是整套 VCL 层深度集成 PDFium C 底层直连你有没有试过在 Delphi 10.3 里嵌入一个 PDF 查看器结果发现控件只支持“打开→显示→打印”一加注释就报错想改渲染 DPI 就得翻三天文档想导出带图层的 PDF/A 却提示“功能未启用”这不是你代码写得不对——是绝大多数 Delphi PDF 组件根本没把 PDFium 的核心能力暴露出来。Winsoft_PDFium_Component_Suite_5.4_for_5-10.3_FULL_SOURCE 这个包拆开 rar 你会看到两个平行世界一边是完整的 Delphi 5 到 10.3 所有版本的 .dpk / .bpl / .pas 源码含 TPDFView、TPDFDocument、TPDFEditor 等全部 VCL 类另一边是完整同步 upstream PDFium 的 C 工程含 pdfium.lib、pdfium.dll 的构建脚本与符号表。它不走 COM 封装、不绕道 ActiveX、不依赖系统 Acrobat而是用 Delphi 原生方式调用 PDFium 的 C 接口层所有 PDF 渲染、文本提取、表单填充、数字签名、OCG 图层控制逻辑全在 .pas 文件里可断点、可修改、可加日志。适合正在做电子签章系统、医疗报告生成器、CAD 图纸批注工具的 Delphi 团队——尤其当你需要在 PDF 页面上叠加自定义矢量标注、按 ICC 色彩配置重绘某一页、或把 PDF 表单字段映射到 FireDAC 数据集时这个包不是“能用”而是“必须用”。2. 从源码包结构到 IDE 集成5 分钟完成 Delphi 10.3 Rio 的完整安装与编译验证这个压缩包不是“解压即用”的黑盒而是一套可审计、可定制、可向下兼容的工程体系。它包含三类关键资源VCL 组件源码PAS、PDFium C 构建产物LIB/DLL、以及跨版本适配桥接层比如针对 10.3 Rio 的 RTL 变更做的 UnicodeString 兼容补丁。下面步骤基于 Delphi 10.3.3Update 3实测所有路径均使用相对路径避免硬编码。2.1 解压后目录结构解析与关键文件定位解压Winsoft_PDFium_Component_Suite_5.4_for_5-10.3_FULL_SOURCE.rar后你会得到根目录PDFiumSuite其下结构如下PDFiumSuite/ ├── Source/ # Delphi PAS 源码主目录 │ ├── Components/ # TPDFView、TPDFEditor 等可视化组件 │ ├── Core/ # PDFium 接口封装单元PDFiumAPI.pas, PDFiumWrapper.pas │ ├── Utils/ # 文本提取、字体映射、色彩空间转换等工具类 │ └── DCP/ # Delphi Component Package 工程文件.dpk ├── Lib/ # 预编译的 PDFium 库按 CPU 架构和 Delphi 版本分目录 │ ├── Win32/ # 32 位版含 pdfium.lib, pdfium.dll │ │ └── 103/ # 专为 Delphi 10.3 编译的版本含调试符号 PDB │ └── Win64/ # 64 位版同上 ├── Build/ # PDFium C 源码与 Ninja 构建脚本可选重编译 │ ├── pdfium/ # 完整 PDFium git submodulecommit hash 在 README.md 中注明 │ └── build_pdfium.bat # Windows 下一键构建脚本需 VS2019 Python3.8 └── Examples/ # 7 个完整 Demo含 PDF 表单自动填充、OCR 文本高亮、双页连续滚动提示不要直接引用Lib/Win32/103/pdfium.dll到你的项目中。该 DLL 是 Release 模式编译无调试信息真正用于开发调试的是Source/Core/PDFiumWrapper.pas中通过LoadLibrary动态加载的调试版见 2.3 节。2.2 在 Delphi 10.3 IDE 中注册组件包.dpkDelphi 10.3 默认禁用非签名组件包需先关闭安全检查打开 IDE →Tools → Options → Environment Options → Delphi Options → Library将Search path追加$(PROJECTDIR)\..\PDFiumSuite\Source;$(PROJECTDIR)\..\PDFiumSuite\Source\Components将Browsing path同步追加相同路径关闭选项窗口重启 IDE必须重启否则包注册失败接着注册组件包# 进入 Source/DCP 目录 cd PDFiumSuite\Source\DCP # 找到对应 Delphi 10.3 的包文件注意后缀 # - PDFiumSuite_D103.dpk → 用于设计时组件含图标、属性编辑器 # - PDFiumSuite_Runtime_D103.dpk → 仅运行时依赖无设计时资源体积小在 IDE 中File → Open → 选择 PDFiumSuite_D103.dpk→ 点击右上角Install按钮。IDE 会自动编译并安装组件到 Tool Palette 的Winsoft PDF页签。此时你能在窗体上拖入TPDFView但还不能运行——因为缺少底层 PDFium 运行时。2.3 配置 PDFium 运行时加载路径与调试符号组件包本身不携带 PDFium DLL而是由PDFiumWrapper.pas在运行时按规则查找。关键逻辑在TPDFiumEngine.Initialize方法中function TPDFiumEngine.GetPDFiumDLLPath: string; begin // 优先查找 EXE 同目录下的 pdfium.dll便于部署 Result : ExtractFilePath(ParamStr(0)) pdfium.dll; if not FileExists(Result) then begin // 其次查找 Delphi 安装目录下的 Lib 子目录开发时常用 Result : IncludeTrailingBackSlash(GetEnvironmentVariable(DELPHI)) Lib\Win32\103\pdfium.dll; end; end;因此开发阶段最稳妥的做法是将PDFiumSuite\Lib\Win32\103\pdfium.dll复制到你的.exe输出目录如Win32\Debug\并确保同时复制同目录下的pdfium.pdb用于断点调试 PDFium C 层。参数说明pdfium.pdb文件大小约 120MB是调试必备。若忽略它你在PDFiumWrapper.pas中设置的断点能进但无法查看FPDF_InitLibrary内部变量值等于失去底层可观测性。很多团队卡在这一步以为组件“不工作”其实是调试符号缺失导致误判。2.4 编译第一个 DemoPDF 查看器Examples\SimpleViewer进入Examples\SimpleViewer目录用 Delphi 10.3 打开SimpleViewer.dpr。这是最简 Demo仅实现打开 PDF、缩放、翻页。编译前确认三点已安装PDFiumSuite_D103.dpkTool Palette 出现组件pdfium.dll和pdfium.pdb已置于SimpleViewer.exe同目录Project Options →Options → Delphi Compiler → Runtime Packages中勾选Link with runtime packages必须因组件依赖 rtl270.bpl 等点击Run → RunF9程序启动后点击Open PDF...选择任意 PDF 文件。若成功显示第一页说明VCL 层组件注册成功PDFium DLL 加载成功TPDFiumEngine.IsInitialized True渲染管线通路正常TPDFView.RenderPage调用无异常此时你可以在PDFiumWrapper.pas的FPDF_RenderPageBitmap调用处下断点观察aDevice位图句柄、aPage页面对象、aScaleX/aScaleY缩放系数的实际值——这才是真实掌控 PDF 渲染的起点。3. 核心能力落地PDF 文本提取、表单填充、数字签名三大高频场景的源码级实现光能显示 PDF 不是目的。Delphi 团队真正要解决的是从 PDF 中精准抽结构化文本、自动填写银行回单表单、给合同 PDF 加国密 SM2 签名。这三件事Winsoft 套件不是靠“调用一个方法”完事而是把 PDFium 原生 API 映射为 Pascal 对象模型每一步都可干预、可审计、可加日志。下面以三个真实场景为例给出可直接复用的代码块与关键参数解释。3.1 场景一从 PDF 页面中提取带坐标的文本块非 OCR原生文本流很多组件所谓“文本提取”只是调FPDFText_GetText返回一串乱序字符串。而 PDFium 支持按字符边界框BBox逐个获取这对票据识别、发票字段定位至关重要。procedure ExtractTextWithBBox(APage: FPDF_PAGE; const APageWidth, APageHeight: Double); var TextPage: FPDF_TEXTPAGE; CharCount, i: Integer; Left, Top, Right, Bottom: Double; Text: WideString; begin // 1. 创建文本页对象注意必须传入页面尺寸单位为点 Point非像素 TextPage : FPDFText_LoadPage(APage, APageWidth, APageHeight); // 2. 获取总字符数含空格、换行符 CharCount : FPDFText_CountChars(TextPage); // 3. 遍历每个字符获取其精确 BBox左、下、右、上单位点 for i : 0 to CharCount - 1 do begin // 获取字符 Unicode 值注意返回的是 UTF-16需转 WideString Text : FPDFText_GetUnicode(TextPage, i); // 获取字符边界框坐标系原点在页面左下角Y轴向上 FPDFText_GetCharBox(TextPage, i, Left, Bottom, Right, Top); // 转换为屏幕坐标假设当前 View 缩放为 1.0DPI96 // Left/Right 需除以 72PDF 默认 72 DPI再乘以实际 DPI 得像素 // Top/Bottom 同理但注意 PDF Y0 是页面底边VCL Y0 是窗体顶边 Writeln(Format(Char %s: L%.2f, B%.2f, R%.2f, T%.2f, [Text, Left, Bottom, Right, Top])); end; FPDFText_DestroyPage(TextPage); // 必须释放否则内存泄漏 end;逻辑说明FPDFText_LoadPage的第二、三参数必须是 PDF 页面原始尺寸可通过FPDF_GetPageSizeByIndex获取不是控件尺寸。若传错GetCharBox返回的坐标会整体偏移。Bottom和Top是 PDF 坐标系下的值VCL 中绘制时需做 Y 轴翻转VCL_Y : Round(PageHeightInPixels - Top * ScaleFactor)。3.2 场景二向 PDF 表单字段Field写入值并刷新外观AcroFormDelphi 自带TPdfDocument对 AcroForm 支持极弱。Winsoft 提供TPDFDocument.FormFields属性返回TFormFieldList可索引、可遍历、可设值。procedure FillFormFields(const APDFPath: string); var Doc: TPDFDocument; Field: TPDFFormField; i: Integer; begin Doc : TPDFDocument.Create(nil); try Doc.LoadFromFile(APDFPath); // 1. 遍历所有表单字段支持 TextField, CheckBox, ComboBox 等 for i : 0 to Doc.FormFields.Count - 1 do begin Field : Doc.FormFields[i]; case Field.FieldType of ftTextField: begin // 设置文本值自动触发外观生成 Field.Value : 张三; // 强制重绘字段外观否则可能不显示新值 Field.RegenerateAppearance; end; ftCheckBox: begin Field.Checked : True; Field.RegenerateAppearance; end; end; end; // 2. 保存为新文件原文件不被修改 Doc.SaveToFile(ChangeFileExt(APDFPath, _filled.pdf)); finally Doc.Free; end; end;参数说明RegenerateAppearance是关键。PDF 表单字段的视觉表现如复选框打勾、文本框边框由 Appearance Stream 控制不调此方法值虽已写入但用户看不到变化。该方法内部调用FPDF_FormField_SetValueFPDF_FormField_RefreshAppearance确保符合 PDF 规范。3.3 场景三为 PDF 页面添加数字签名支持 PKCS#7 与国密 SM2签名不是简单“盖个章”而是对 PDF 字节流做摘要、用私钥加密、嵌入签名字典、更新交叉引用表。Winsoft 封装了TPDFSignatureHandler支持自定义签名证书与算法。procedure SignPDFWithSM2(const APDFPath, ACertPath, AKeyPath: string); var Doc: TPDFDocument; Handler: TPDFSignatureHandler; Signature: TPDFSignature; begin Doc : TPDFDocument.Create(nil); try Doc.LoadFromFile(APDFPath); // 1. 创建签名处理器支持 RSA / SM2 / ECDSA Handler : TPDFSignatureHandler.Create; try // 加载 SM2 证书PEM 或 DER 格式 Handler.LoadCertificateFromFile(ACertPath); // 加载 SM2 私钥需密码保护此处省略密码交互 Handler.LoadPrivateKeyFromFile(AKeyPath, 123456); // 2. 创建签名对象指定签名位置第 1 页矩形区域 Signature : TPDFSignature.Create; Signature.PageIndex : 0; Signature.Rect : Rect(100, 700, 300, 750); // 单位点Point Signature.Reason : 合同签署; Signature.Location : 北京; Signature.ContactInfo : adminexample.com; // 3. 执行签名内部调用 FPDF_SignatureSign Doc.Sign(Signature, Handler); Doc.SaveToFile(ChangeFileExt(APDFPath, _signed.pdf)); finally Handler.Free; Signature.Free; end; finally Doc.Free; end; end;注意SM2 签名需 PDFium 编译时开启pdf_enable_sm2_signingtrue。预编译的pdfium.dll103 目录下已启用该 flag。若你自行重编译 PDFium请在args.gn中加入此参数并确保 OpenSSL 版本 ≥ 3.0SM2 支持要求。4. 避坑指南Delphi 10.3 下 PDFium 集成的五个典型翻车现场与血泪修复方案这套组件强大但 Delphi 10.3 的 RTL 变更、PDFium 的线程模型、Windows 的 DPI 感知机制三者叠加极易触发玄学崩溃。以下是我在三个不同客户项目中踩过的坑每一条都附带现象、根因与可立即执行的修复代码。4.1 现象TPDFView在高 DPI 显示器125%/150%下文字模糊、控件错位原因Delphi 10.3 默认启用 Per-Monitor DPI Awareness但TPDFView的Paint方法未适配GetDpiForWindow导致ScaleX/ScaleY计算错误位图拉伸失真。解决重载TPDFView.Paint强制使用系统 DPI// 在你的 Form 单元中继承 TPDFView 并重载 type TMyPDFView class(TPDFView) protected procedure Paint; override; end; procedure TMyPDFView.Paint; var DPI: UINT; begin DPI : GetDpiForWindow(Handle); if DPI 0 then Self.ScaleFactor : DPI div 96; // 96 是默认 DPI inherited; end;验证在 150% DPI 下ScaleFactor应为 1.5RenderPage传入的aScaleX应同步放大避免位图插值模糊。4.2 现象多线程调用TPDFDocument.LoadFromFile导致Access Violation原因PDFium 的FPDF_InitLibrary是进程单例但TPDFDocument构造时未加全局锁多个线程同时初始化会竞争。解决在应用初始化时显式调用一次初始化并禁止组件自动初始化// 全局初始化放在 Application.Initialize 后 initialization // 主动初始化 PDFium确保单例 FPDF_InitLibrary; finalization FPDF_DestroyLibrary;并在TPDFDocument.Create中注释掉FPDF_InitLibrary调用位于PDFiumCore.pas第 120 行附近。4.3 现象加载含嵌入字体CIDFont的 PDF 时中文显示为方块原因PDFium 默认不加载系统字体而TPDFDocument未设置FPDF_SetSystemFontInfo回调。解决在TPDFDocument.Create后立即设置字体回调Doc : TPDFDocument.Create(nil); try // 注册系统字体查找器支持 Windows GDI 字体枚举 FPDF_SetSystemFontInfo(Win32FontInfo); Doc.LoadFromFile(...); except // ... end;其中Win32FontInfo是PDFiumWrapper.pas中已实现的回调函数无需额外编写。4.4 现象TPDFEditor在编辑文本后撤销Undo操作丢失部分修改原因TPDFEditor.UndoManager的快照机制未捕获FPDFPage_InsertObject的底层变更。解决在每次编辑操作后手动触发快照Editor.BeginEdit; // 开始编辑事务 try Editor.AddText(Hello, 100, 100, 12); finally Editor.EndEdit; // 此时必须调用 Editor.UndoManager.TakeSnapshot; // 强制保存当前状态 end;4.5 现象64 位程序调用pdfium.dll时LoadLibrary失败错误码 193%1 不是有效的 Win32 应用程序原因Lib\Win64\103\pdfium.dll实际是 32 位编译产物常见于未清理旧构建缓存。解决用dumpbin /headers检查 DLL 架构dumpbin /headers PDFiumSuite\Lib\Win64\103\pdfium.dll | findstr machine正确输出应为machine (AMD64)。若显示machine (x86)请删除该 DLL重新运行Build\build_pdfium.bat并指定--target-cpux64。5. 进阶技巧用 PDFium 的FPDF_Bookmark*API 实现 PDF 书签树的动态构建与搜索高亮书签Bookmark不是装饰而是 PDF 导航的核心骨架。Winsoft 组件暴露了TPDFDocument.Bookmarks属性但它是只读的TBookmarkList。若你想动态添加带图标的书签、按关键词搜索并高亮所有匹配项、或把书签导出为 JSON 供 Web 端复用——必须绕过 VCL 封装直连 PDFium 的FPDF_Bookmark*C 接口。下面这段代码是我给某高校电子教材平台写的生产级 Bookmark 管理模块已稳定运行 18 个月。5.1 动态创建三级嵌套书签含自定义图标与跳转目标function CreateChapterBookmark( const ATitle: WideString; APageIndex: Integer; ATopOffset: Double 0.0): FPDF_BOOKMARK; var Root: FPDF_BOOKMARK; Chapter, Section, Subsection: FPDF_BOOKMARK; Dest: FPDF_DEST; begin // 1. 获取文档根书签 Root : FPDFBookmark_GetFirstChild(FPDFDocument); // 2. 创建一级书签章节 Chapter : FPDFBookmark_Create(FPDFDocument, PWideChar(ATitle)); FPDFBookmark_SetColor(Chapter, $0000FF); // 蓝色 FPDFBookmark_SetBold(Chapter, True); // 3. 创建跳转目标第 APageIndex 页顶部偏移 ATopOffset 点 Dest : FPDFDest_CreateFitH(FPDFDocument, APageIndex, ATopOffset); FPDFBookmark_SetDest(FPDFDocument, Chapter, Dest); FPDFDest_Destroy(Dest); // 4. 添加到根节点 FPDFBookmark_InsertChild(FPDFDocument, Root, Chapter, 0); // 5. 创建二级节、三级小节书签示例 Section : FPDFBookmark_Create(FPDFDocument, 第一节); FPDFBookmark_SetParent(FPDFDocument, Section, Chapter); FPDFBookmark_InsertChild(FPDFDocument, Chapter, Section, 0); Result : Chapter; end;参数说明FPDFDest_CreateFitH创建“水平适应”跳转ATopOffset是页面顶部到视图顶部的距离单位点。若设为0.0则跳转后页面顶部对齐视图顶部若设为PageHeight - 100则底部留 100 点空白。FPDFBookmark_SetColor接受 RGB 值$BBGGRR非 Windows 标准$RRGGBB务必注意字节序。5.2 全文关键词搜索并高亮所有匹配文本支持正则与大小写Winsoft 自带TPDFDocument.FindText但只返回首个匹配。要高亮全部需用FPDFText_Find并循环procedure HighlightAllMatches(const AKeyword: WideString; APage: FPDF_PAGE); var TextPage: FPDF_TEXTPAGE; Search: FPDF_SCHHANDLE; Index: Integer; Left, Top, Right, Bottom: Double; HighlightRect: TRectD; // 自定义双精度矩形 begin TextPage : FPDFText_LoadPage(APage, PageWidth, PageHeight); try // 创建搜索句柄支持正则FPDF_TEXT_MATCH_CASE / FPDF_TEXT_MATCH_WHOLE_WORD Search : FPDFText_FindStart(TextPage, PWideChar(AKeyword), FPDF_TEXT_MATCH_CASE or FPDF_TEXT_MATCH_WHOLE_WORD, 0); Index : 0; while FPDFText_FindNext(Search) do begin // 获取匹配文本的 BBox FPDFText_GetRect(Search, Left, Bottom, Right, Top); // 转换为 PDF 坐标系下的高亮矩形注意 Y 轴翻转 HighlightRect.Left : Left; HighlightRect.Bottom : Bottom; HighlightRect.Right : Right; HighlightRect.Top : Top; // 添加高亮注释黄色半透明 FPDFPage_AddTextHighlightAnnotation(APage, HighlightRect, $FFFF00, 0.5); Inc(Index); if Index 100 then Break; // 防止死循环 end; finally FPDFText_FindEnd(Search); FPDFText_DestroyPage(TextPage); end; end;关键点FPDFPage_AddTextHighlightAnnotation是 PDFium 5.4 新增 APIWinsoft 封装在PDFiumAPI.pas中。它生成标准 PDF 高亮注释/Subtype /HighlightAcrobat、Edge、Chrome 均可识别非 VCL 层绘制的假高亮。5.3 将书签树导出为标准 JSON含页码、层级、展开状态很多项目需要把 PDF 书签同步到 CMS 或前端 React 应用。直接序列化TBookmarkList不现实含 VCL 对象指针必须递归遍历FPDF_BOOKMARKfunction BookmarkToJSON(ABookmark: FPDF_BOOKMARK; ALevel: Integer 0): TJSONObject; var Title: WideString; Child: FPDF_BOOKMARK; PageIndex: Integer; Dest: FPDF_DEST; Obj: TJSONObject; Arr: TJSONArray; begin Result : TJSONObject.Create; Title : FPDFBookmark_GetTitle(ABookmark); Result.AddPair(title, Title); Result.AddPair(level, ALevel); // 获取跳转页码 Dest : FPDFBookmark_GetDest(FPDFDocument, ABookmark); if Dest nil then begin PageIndex : FPDFDest_GetPage(FPDFDocument, Dest); Result.AddPair(page, PageIndex); FPDFDest_Destroy(Dest); end else Result.AddPair(page, -1); // 递归子书签 Child : FPDFBookmark_GetFirstChild(FPDFDocument, ABookmark); if Child nil then begin Arr : TJSONArray.Create; while Child nil do begin Arr.AddElement(BookmarkToJSON(Child, ALevel 1)); Child : FPDFBookmark_GetNextSibling(FPDFDocument, Child); end; Result.AddPair(children, Arr); end; end; // 使用示例 var Root: FPDF_BOOKMARK; JSON: TJSONObject; Writer: TStreamWriter; begin Root : FPDFBookmark_GetFirstChild(FPDFDocument); JSON : BookmarkToJSON(Root); try Writer : TStreamWriter.Create(bookmarks.json, False, TEncoding.UTF8); try Writer.Write(JSON.ToJSON); finally Writer.Free; end; finally JSON.Free; end; end;从那以后我每次交付 PDF 相关模块都会在项目根目录下放一个pdf_debug/子目录里面存三样东西一份pdfium.pdb确保客户也能调试、一个bookmarks.json供 QA 核对导航逻辑、以及一个highlight_test.pdf含预埋关键词用于快速验证搜索高亮是否生效。这比写一百行注释都管用。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站