65.9K
CodeProject 正在变化。 阅读更多。
Home

将 MuPDF DLL 编译成渲染和编辑 PDF 文档

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.71/5 (27投票s)

2017 年 11 月 18 日

CPOL

10分钟阅读

viewsIcon

84991

downloadIcon

4121

MuPDF 是一个开源、高性能的 PDF 渲染和编辑引擎,用 C 语言编写。本文介绍了如何将其源代码编译成 DLL,以便在其他编程语言中使用。

关于下载的说明

下载包含一个预编译的 MuPDF DLL(版本为 1.19)和一个简单的 C# 演示项目,该项目利用 DLL 中的功能将 PDF 文档转换为图像文件。

作为下载上述文件的替代方案,您还可以克隆我在 GitHub 上的仓库,获取所有需要的代码文件,并开始使用 MuPDF.sln 解决方案文件。

关于 SumatraPDF 的说明

一篇先前撰写的文章讨论了从 SumatraPDF 项目(该项目大量使用了 MuPDF)中提取 DLL 文件的可能性。通过使用 Visual Studio 2019 编译 SumatraPDF 项目,可以非常轻松地获取一个名为 libmupdf.dll 的 MuPDF DLL 文件。

我们需要什么

MuPDF 的源代码可以从其官方网站GitHub.com 上的镜像下载。以下列表包含编译 MuPDF 源代码所需的所有内容。

  1. Visual Studio 2019,包含C++桌面开发工作负载。
  2. Windows 10 SDK.
  3. (可选,但推荐)Python,用于提取函数名称到定义文件,以便编译 DLL 文件。
  4. 硬盘上约 1GB 的可用空间用于代码编译。

编译源代码

MuPDF 的源代码被分成几个目录,包含成千上万个代码文件。

  1. source:C 语言代码文件
  2. include:头文件
  3. thirdparty:相关开源项目的代码文件
  4. platform:代码编译项目
  5. resources:引擎使用的资源(字体、字符映射、颜色配置文件、PDF 名称等)
  6. scripts:一些帮助编译的代码文件

相关项目文件

导航到 platform/win32 目录,您会看到不少 C 语言项目文件和一个名为 mupdf.sln 的解决方案文件。

注意

我建议您复制一份 mupdf.sln,并在此副本上进行后续操作。

切勿修改源代码,除非您知道自己在做什么,并希望为 MuPDF 项目做出贡献。如果您修改了源代码,以后在想要与 MuPDF 项目保持同步时,可能会在合并源代码时遇到问题。

打开该解决方案文件,您会看到加载了 10 多个项目。

编译 DLL 文件最重要的项目如下所示

  1. libmupdf:编译静态库文件 libmupdf.lib 的项目,该库将用于编译 DLL 文件
  2. libresources:处理资源的库项目,供 libmupdf 使用
  3. libthirdparty:相关开源库项目,供 libmupdf 使用
  4. bin2coff:自动生成其他项目所需字体资源文件的项目。

如果您的目标仅是编译 MuPDF DLL 文件,那么解决方案中的其余项目都可以忽略。因此,您可以安全地卸载或从解决方案中删除它们。

为了处理它们之间的依赖关系,项目必须按照上面列出的相反顺序进行编译,从 bin2cofflibmupdf

编译源项目

在 MuPDF 1.17 之前,我使用 Windows 7 SDK 编译源代码,并且需要升级项目文件才能成功编译。从 MuPDF 1.17 开始,使用了 Windows 10 SDK,Visual Studio 2019 成为官方支持的编译器。我们可以毫无问题地使用 Visual Studio 2019 编译它们。

关于缺失的代码文件:如果您下载的是源代码,则需要搜索网络并下载所有必需的第三方源代码文件。因此,建议使用 Visual Studio 克隆项目,而不是下载。

创建 DLL

现在我们非常接近目标了。

要从静态库文件获取动态库文件,我们需要创建另一个项目。

提示

我不修改 libmupdf 项目使其生成 DLL 文件,是因为我想让解决方案中引用 libmupdf 的其他项目仍然可以编译,并在以后同步源代码文件时(当 MuPDF 源代码更新时)简化过程。

要创建 DLL 文件,我们将需要做三件事

  1. 创建一个新项目以输出 DLL 文件。
  2. 在该项目中引用相关的静态库文件。
  3. 定义将在 DLL 文件中导出的函数。

设置 DLL 项目

要创建 DLL 文件,我们在 MuPDF 解决方案中创建一个新的 C 项目。我在我的解决方案中简单地将其命名为 MuPDFLib

通过选择我们上面创建的 MuPDFLib 项目并点击“项目”菜单选择“属性”命令,按以下列表修改项目。

  1. 选择所有配置所有平台
  2. 在 Platform Toolset 中,使用Visual Studio 2019 (v142)
  3. 如果 SDK 版本不是 10,请将其更改为10
  4. 将配置更改为动态库 (.dll)
  5. 切换到项目属性对话框中的链接器/输入部分,并将模块定义文件属性设置为“libmupdf.def”(我们稍后将生成此文件)。
  6. 单击确定按钮关闭项目属性对话框。

引用相关的静态库文件

在解决方案资源管理器中右键单击 MuPDFLib 项目的引用。从弹出的上下文菜单中,选择添加引用命令,这将打开一个对话框。在该对话框中,勾选 libmupdflibresourceslibthirdparty 前面的复选框,如下图所示。

创建 DLL 函数的定义文件

上述设置还不能编译出一个可用的 DLL 文件,除非我们创建项目引用的缺失的 libmupdf.def 函数定义文件。定义文件是一个列表,用于定义可以从编译的 DLL 文件导出的函数。

MuPDF 项目中的函数位于 include 文件夹的头文件中。然而,由于该项目包含相当多的头文件,手动提取这些函数名称不是一件轻松的任务。

幸运的是,SumatraPDF(一个基于 MuPDF 的 PDF 查看器应用程序)的开发人员创建了一个 Python 脚本来为我们生成这个 def 文件。您可以从 SumatraPDF 的仓库复制脚本文件,并将其放置在您存储 MuPDF 源代码的 scripts 文件夹中。

脚本需要一些修改才能反映 MuPDF 的最新更改。我已将我的版本上传到我的 GitHub 仓库。如果您已经在计算机上安装了 Python 2.7,请将脚本文件 gen_libmupdf.def.pyutil.py 放入 scripts 文件夹,双击 gen_libmupdf.def.py,它将在 platform/win32 文件夹中生成 def 文件。

生成 def 文件后,我们就可以开始编译 DLL 文件了。

注意

编译时可能会遇到一些 LNK2001 错误,表明某些函数未解析。只需从自动生成的 def 文件中删除这些函数即可继续。

如果您没有 Python 并且不想安装它,则可能需要使用代码编辑器手动编写 def 文件,或编写自己的应用程序来生成 def 文件。

我建议您使用 Python 脚本来完成这项繁琐的工作。

最终,您将在 platform/win32/Release(或 platform/win32/Debug 等)文件夹中获得 DLL 文件。DLL 文件的位置取决于您的编译配置。

检查导出的函数

至此,我们已经获得了 MuPDF 引擎的 DLL 文件。您可以使用 NirSoft 开发的一个小型实用程序 DLL Export Viewer 来检查函数是否已由 DLL 文件导出。

在 DLL Export Viewer 中导出的函数可能如下所示

通过排除不需要的字体来缩小 DLL 文件

有些人可能会注意到编译后的 DLL 文件有点大,高达约 34MB。它占用这么多空间的原因是它嵌入了大量字体以支持国际字符。我们可以通过从编译后的 DLL 中排除这些字体文件,将其大小缩小到约 8MB。

要制作自定义 DLL,请打开 libmupdf 项目,展开 !include/fitz 文件夹,然后点击 config.h 文件。您会看到大量的注释和定义指令。向下滚动到带有文本“选择要包含的字体”的注释,在其下方,有一些被注释掉的行,如下所示

/*
    Choose which fonts to include.
    By default we include the base 14 PDF fonts,
    DroidSansFallback from Android for CJK, and
    Charis SIL from SIL for epub/html.
    Enable the following defines to AVOID including
    unwanted fonts.
*/
/* To avoid all noto fonts except CJK, enable: */
/* #define TOFU */

如其所示,通过定义 TOFU;TOFU_CJK_EXT,您将从 DLL 文件中排除几个巨大的 noto 字体和 CJK 扩展字体,并将输出大小从 34MB 减少到约 8MB。

警告

请谨慎遵循源代码中的说明:启用以下定义以避免包含不必要的字体。

如果您通过取消注释上面那行下面的行来修改源代码,您在以后同步更新的源代码时会遇到源代码冲突。

我建议您不要修改源代码;而是修改 libmupdf 项目属性,并在预处理器定义属性中添加定义,如下图所示。注意“TOFU”之前的“;”,它将定义与<不同的选项>分隔开。

重新编译 MuPDFLib 项目,并检查 DLL 文件的大小。它应该会小很多。

使用 DLL 文件中的函数

我不会在这篇文章中写太多关于如何使用 DLL 中函数的内容。对于 C# 程序员,您可以使用平台调用技术。先前,我写了一篇题为使用 P/Invoke 调用 MuPDF 库渲染 PDF 文档的文章。您可以点击上面的链接进行参考。

本文顶部的下载链接包含一个示例项目,演示了如何从 C# 使用 P/Invoke 来调用编译的 DLL 文件中的函数。

与 MuPDF 项目保持同步

随着 MuPDF 项目的不断发展,源代码可能会发生变化。

以下是与 MuPDF 项目保持同步的简要总结。

  1. 如果您的源代码是从 GitHub 克隆的,请更新它;否则,您可以从官方网站下载源代码并覆盖现有代码文件。我更喜欢前者,因为它在更新时下载的字节更少。
    1. 更新源代码时,将 GitHub 源代码合并到您的仓库。
    2. 由于您在上述过程中修改了 libmupdf 项目以缩小 DLL 的大小,因此会发生源代码冲突。我们必须通过合并源代码来解决冲突。合并时使用(官方代码)。
    3. 不要忘记更新子模块,方法是右键单击团队资源管理器更改窗格中的已更新子模块,然后执行相应的命令,否则您的项目可能无法编译。在解决任何子模块冲突时,请使用
  2. 如有必要,请执行 gen_libmupdf.def.py 脚本,为DLL导出重新生成 def 文件。
  3. 如果您想缩小输出的 DLL 文件,请通过定义与字体相关的预处理器定义来调整 libmupdf 项目。
  4. 重新编译 MuPDFLib 项目并获取 DLL 文件。
  5. 如果遇到 LNK2001 错误,请从 def 文件中删除不存在的函数。
  6. 检查 MuPDF 项目的提交历史,查看项目中的头文件(*.h 文件)是否已更改。发生更改时,通过比较提交历史来找出已更改的内容。
  7. 如果 MuPDF 的版本发生变化,则必须更新您的源代码以适应新的 MuPDF 项目API

历史

  1. 首次发布于 2017 年 11 月
  2. 更新了 GitHub 分支中的源代码,并修复了字体资源部分中的拼写错误。
  3. 更新了 GitHub 分支中的源代码,重新编译了 DLL,更新了文章以反映 2018 年 11 月 24 日的最新源代码更改。
  4. 更新了 GitHub 分支中的源代码,重新编译了 DLL,更新了文章以添加更多关于与 MuPDF 项目同步的详细信息,并反映 2019 年 7 月 18 日的最新源代码更改。
  5. 将 GitHub 分支中的源代码更新到 MuPDF 1.16,重新编译了 DLL,在演示项目中修复了 P/Invoke 调用约定问题,于 2019 年 8 月 1 日。
  6. 修改了文章,并将 GitHub 分支中的源代码更新到 MuPDF 1.17rc,于 2020 年 4 月 28 日重新编译了 DLL。
© . All rights reserved.