在 .NET Core 上使用 C# 读取 PDF

2025-06-08

在 .NET Core 上使用 C# 读取 PDF

任何尝试使用 C# 从 PDF 中提取文本的人都会问自己一个问题:为什么这如此复杂?

这是一个好问题,答案在于设计 PDF 格式时所做的权衡。

对于不熟悉 PDF 的人来说,我会将 PDF 文件描述为一张图片。从高层次上讲,它是一组定义文档页面显示方式的图像。这意味着无论您在 Windows、Linux、Chrome、Android 等平台上查看,它看起来都应该(或多或少)相同。它包含文本和字体信息几乎(但并非完全)是偶然的。

文件中的字体有助于显示 PDF 的应用程序在各个平台上以(几乎)相同的方式绘制文本。文档中包含的文本内容主要只是定义了字体中字母的绘制位置。甚至有些文档包含的字体信息与显示的字形没有任何实际关系,您可能以前遇到过这种情况;如果您在这些文档中突出显示并复制粘贴一些文本,而这些文本在粘贴到另一个应用程序时看起来“正常”,那就完全是无稽之谈。

考虑到这一点,从 PDF 中提取“完美”(或者很多时候甚至勉强过得去)的文本根本不存在。它们的设计初衷并非以实用的方式传输文本,它很大程度上只是渲染文档(即使文档中包含文本)需求的副作用。

出于这个原因,有些人只是对所有 PDF 文档运行 OCR,并依靠 OCR 从图像中提取文本,我在这里重复一遍。

如果您不想运行 OCR,也不想为商业许可的 PDF 软件花费大量金钱,那么您可以使用哪些选项在 C# 中从 PDF 中获取文本?

选项

对于以下示例,我使用 Visual Studio 2017 在 Windows 10 上针对 .NET Core 2.1。我将使用此处的示例 PDF ,但您可以使用任何 PDF 文件。

对于下文关于许可的讨论,我在此声明:我不是律师,对软件许可也不太了解。如果您真的遇到许可问题,请咨询了解这方面知识的人。

iTextSharp

关联

原版。C# 中较为成熟的 PDF 库之一。iTextSharp(从版本 7 开始为 iText)的大多数版本都受AGPL的约束。这是一个相当“激进”的许可证,除非您将整个源代码也以源代码形式发布(这种说法颇具争议,我并不认为 AGPL 是开源的),或者购买商业许可证,否则不能用于商业用途。

在更改为 AGPL 许可证之前,iTextSharp有一个非官方的分支,当时它是 LGPL 许可证(这仍然是一个版权许可证- 请注意,此链接指向 LGPL v2.1 而不是 v2),最近进行了一些更改以将其移植到 .NET Core。

dotnet add package iTextSharp.LGPLv2.Core

安装软件包后,您可以参考GitHub 上的示例来完成大多数任务。以下代码从磁盘打开一个文件,并将文本内容写入控制台:

// Create a reader from the file bytes.
var reader = new PdfReader(File.ReadAllBytes(@"..\..\..\sample.pdf"));

for (var pageNum = 1; pageNum <= reader.NumberOfPages; pageNum++)
{
    // Get the page content and tokenize it.
    var contentBytes = reader.GetPageContent(pageNum);
    var tokenizer = new PrTokeniser(new RandomAccessFileOrArray(contentBytes))

    var stringsList = new List<string>();
    while (tokenizer.NextToken())
    {
        if (tokenizer.TokenType == PrTokeniser.TK_STRING)
        {
            // Extract string tokens.
            stringsList.Add(tokenizer.StringValue);
        }
    }

    // Print the set of string tokens, one on each line.
    Console.WriteLine(string.Join("\r\n", stringsList));
}

reader.Close();

iTextSharp API 一直以来都让我感觉有点难以理解,而且它的许可证对我来说也有点难以接受,即使遵循 LGPL 而不是 AGPL。不过,你可以使用功能最强大、功能最齐全的 C# PDF 库之一。

PDF猪

关联

免责声明:我是这个软件包的维护者。

PdfPig 是一个基于Apache 2.0许可证的库,最初是为了尝试将 Java PDFBox 项目移植到 C# 平台而创建的。我构建 PdfPig 时主要专注于从 PDF 中提取文本。其他用例(例如创建 PDF)的支持不太好,或者 PDF 转图像或 HTML 转 PDF 则完全不受支持。

首先从 NuGet 获取包:

dotnet add package PdfPig

然后打开并提取文本,就像我们对之前的库所做的那样:

using (var pdf = PdfDocument.Open(@"..\..\..\sample.pdf"))
{
    foreach (var page in pdf.GetPages())
    {
        // Either extract based on order in the underlying document with newlines and spaces.
        var text = ContentOrderTextExtractor.GetText(page);

        // Or based on grouping letters into words.
        var otherText = string.Join(" ", page.GetWords());

        // Or the raw text of the page's content stream.
        var rawText = page.Text;

        Console.WriteLine(text);
    }

}

PdfPig 提供了多种文本提取策略。移植优秀的 PDFBoxPDFTextStripper仍是一个悬而未决的问题,但 PdfPig 提供了丰富的基于字母的 API,支持任何自定义的文本提取逻辑。

每一页都包含字母及其在页面上的确切位置,以及几乎所有您可能需要的信息。鉴于以可靠的顺序提取文本内容的难度,PdfPig 的设计使您能够以任何您需要的方式提取 PDF 文本,并允许您构建自己的后处理流程,以便为您的用例提供最佳结果。

文档网

关联

docnet 封装了Chromium 使用的PDFium C++ 库。它提供了 C# API 来实现 C++ 库中的功能。这个遵循 MIT 许可证的封装器封装了遵循 Apache 2.0 许可证的 PDFium 代码,因此是完全开源的。

dotnet add package Docnet.core

然后,您可以从每个页面中提取内容,或者直接访问字母:

using (var docReader = DocLib.Instance.GetDocReader(@"..\..\..\sample.pdf", new PageDimensions()))
{
    for (var i = 0; i < docReader.GetPageCount(); i++)
    {
        using (var pageReader = docReader.GetPageReader(i))
        {
            var text = pageReader.GetText();
            Console.WriteLine(text);
        }
    }
}

docnet 不仅能让您享受原生库的速度优势,还能让您安心运行 Chromium 及其扩展版 Chrome 所支持的 PDF 代码。目前,它限制您只能使用 x64 平台,但未来可能会有所改进。

PDFSharp

关联

这是 MIT 许可的 PdfSharp 库到 .NET Core 的移植。它似乎主要专注于创建(而非读取)PDF,但也支持其他操作。它还将原始 PDfSharp 的 System.Drawing 依赖项替换为跨平台更友好的 ImageSharp 库;这意味着,像往常一样,您应该检查依赖项的许可证(最近有一些关于更改 ImageSharp 许可证的讨论)。

我找不到一个用于文本提取的明显的 API,并且似乎存在一个文本提取的未解决的问题,但如果您想将 PDF 转换为图像,或者使用内部 PDF 结构,我想我会将其作为一个选项提及。

结论

我们回顾了开发人员在 .NET Core 上使用 C# 读取 PDF 文本时可用的几种方案。要找到合适的开源软件(而非商业或版权许可软件)来完成这项任务,确实有些困难。

即使我们找到一个库,它仍然无法 100% 完美地按阅读顺序提取文本,因为 PDF 从未被设计为支持这一点。

我已经包含了我知道的选项,但如果您觉得我遗漏了任何选项,请在评论中告诉我。

我希望本文能帮助您编写出色的软件,将 PDF 的强大功能带给人们!

鏂囩珷鏉ユ簮锛�https://dev.to/eliotjones/reading-a-pdf-in-c-on-net-core-43ef
PREV
我最喜欢的 5 份新闻通讯,用于了解前端开发的最新动态
NEXT
2021 年 10 个重要的全栈 Web 开发工具