【问题标题】:PDF parsing in C++ (PoDoFo)C++ 中的 PDF 解析 (PoDoFo)
【发布时间】:2012-07-30 04:53:07
【问题描述】:

嗨,我正在尝试从一些 pdf 中解析一些文本,我想使用 PoDoFo,现在我尝试搜索如何使用 PoDoFo 解析 pdf 的示例,但是我能想出的只是示例如何创建和编写不是我真正需要的 pdf 文件。

如果有人有任何使用 PoDoFo 解析 PDF 文件的教程或示例,或者对我可以使用的其他库有建议,请告诉我。我也知道 linux 上有 pdftotext,但是,我不仅不能使用它,而且我更希望能够在内部完成我需要做的所有事情,而不是依赖正在安装的外部程序。

【问题讨论】:

  • 你看过SumatraPDF吗?它是开源的(尽管 GPL - 请参阅 repo)。
  • 我没有,但从它的外观来看,它只适用于 Windows,这不是我想要的。不过谢谢!

标签: c++ parsing pdf podofo


【解决方案1】:

PoDoFo 没有提供从文档中轻松提取文本的方法,但并不难做到。

将文档加载到PdfMemDocument

PoDoFo::PdfMemDocument pdf("mydoc.pdf");

遍历每一页:

for (int pn = 0; pn < pdf.GetPageCount(); ++pn) {
    PoDoFo::PdfPage* page = pdf.GetPage(pn);

遍历该页面上的所有 PDF 命令:

    PoDoFo::PdfContentsTokenizer tok(page);
    const char* token = nullptr;
    PoDoFo::PdfVariant var;
    PoDoFo::EPdfContentsType type;
    while (tok.ReadNext(type, token, var)) {
        switch (type) {
            case PoDoFo::ePdfContentsType_Keyword:
                // process token: it contains the current command
                //   pop from var stack as necessary
                break;
            case PoDoFo::ePdfContentsType_Variant:
                // process var: push it onto a stack
                break;
            default:
                // should not happen!
                break;
        }
    }
}

“进程令牌”和“进程变量”cmets 是它变得更复杂的地方。您将获得要处理的原始 PDF 命令。幸运的是,如果您实际上并没有渲染页面并且您想要的只是文本,您可以忽略其中的大部分。您需要处理的命令是:

BT, ET, Td, TD, Ts, T, Tm, Tf, ", TJ, @9867654336@, @987654334

BTET 命令标记文本流的开始和结束,因此您希望忽略不在 BT/ET 对之间的任何内容。

PDF 语言基于 RPN。命令流由压入堆栈的值和将值从堆栈中弹出并处理它们的命令组成。

"'TjTJ 命令是唯一实际生成文本的命令。 "'Tj 返回单个字符串。使用var.IsString()var.GetString() 进行处理。

TJ 返回一个字符串数组。您可以使用以下方法提取每个:

if (var.isArray()) {
    PoDoFo::PdfArray& a = var.GetArray();
    for (size_t i = 0; i < a.GetSize(); ++i)
        if (a[i].IsString())
            // do something with a[i].GetString()

其他命令用于确定何时引入换行符。 "' 也引入了换行符。最好的办法是从 Adob​​e 下载 PDF 规范并查找文本处理部分。它更详细地解释了每个命令的作用。

我发现编写一个小程序非常有帮助,该程序获取 PDF 文件并转储每个页面的命令流。

注意:如果您所做的只是提取没有定位信息的原始文本,您实际上不需要维护一堆var 值。所有的文本渲染命令最多只有一个参数。您可以简单地假设var 中的最后一个值包含当前命令的参数。

【讨论】:

  • 感谢您写得很好的解释!如果我需要澄清,我会在接下来几天尝试后接受您的回答
  • @Ferruccio ,安静的详细而有帮助的答案,您能否也添加一些信息,如果图像也有操作符以及如何识别它们?
  • @codin - 我没有处理过 PDF 文件中的图像,所以我不能给你详细的答案。我建议在 PDF 规范中查找图像(第 8.9 节:图像)。
  • @Ferruccio,谢谢,我发现 Do 运算符用于图像。但是移除图像对象以外的艺术品变得越来越困难,比如文本背后的背景等。
  • 当我处理文本时,我将大部分单词分解为一个数组中的多个对象,而不考虑空格。例如:(e)(v)(en)(inef)(f)(ectiv)(e)(until)(w)(e)(unders)(t)(ood)(some)(of)(its) (im)(por)(tant)(dif)(f)(erences)。这是在具有 TJ 标签的单个变体中。是否还有其他地方包含带有 TJ 标签的空白信息?
【解决方案2】:

我没有使用过 PoDoFo,但是快速浏览他们 API 网页上的类层次结构会发现:

void PoDoFo::PdfMemDocument::Load( const char * pszFilename )

(API doc link)

所以我在这里冒险猜测一下,你会这样做:

PoDoFo::PdfMemDocument doc;
doc.Load( "somefile.pdf" );

然后我想您通过调用 doc.GetObjects() 并遍历该数组 (see PdfDocument class) 来导航文档树

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-31
    • 2023-01-24
    • 2013-05-26
    • 1970-01-01
    • 2015-11-01
    • 2011-03-18
    • 1970-01-01
    • 2014-03-29
    相关资源
    最近更新 更多