我正在尝试了解 Poppler 及其(缺乏)文档。
我想做的是一件非常简单的事情:打开一个PDF文件并阅读其中的文本。然后我将处理文本,但这在这里并不重要。
所以...我看到了
poppler_page_get_text
函数,它有点工作,但我必须指定一个选择矩形,这不是很方便。难道不是有一个非常简单的函数可以按顺序输出 PDF 文本(也许是逐行?)。
您应该能够将选择矩形设置为页面的
pageSize/MediaBox
并获取所有文本。
我说应该是因为在你开始想知道为什么你会对
poppler_page_get_text
的输出感到惊讶之前,你应该知道文本是如何在页面上布局的。所有图形均使用以后修复符号表示的程序布置在页面上。为了渲染页面,该程序在空白页面上执行。
程序中的操作可以包括改变颜色、位置、当前变换矩阵、绘制直线、贝塞尔曲线等。文本由一系列文本运算符布局,这些运算符始终用 BT(开始文本)和 ET(结束文本)括起来。文本在页面上的放置方式或位置由生成 PDF 的软件自行决定。例如,对于打印驱动程序,代码响应 GDI 调用
DrawString
并将其转换为文本绘制操作。
如果幸运的话,页面上的文本会以合理的顺序排列并使用合理的字体,但许多生成 PDF 的程序并不那么友好。
Psroff
,例如喜欢先放置所有纯文本,然后是斜体文本,然后是粗体文本。单词可能会也可能不会按阅读顺序排列。字体可以重新编码,以便 'a'
映射到 '{'
或其他。然后,您可能会使用多个字符被单个字形替换的连字 - 最常见的是 ae
、oe
、fi
、fl
和 ffl
。
完成所有这些后,提取文本的过程绝对不平凡,因此,如果您看到文本提取的质量较差,请不要感到惊讶。
我曾经在 Acrobat 1.0 和 2.0 中使用文本提取工具 - 要正确使用它确实是一个挑战。
仅供记录,我现在正在使用 poppler 和这个小程序
#include <iostream>
#include "poppler-document.h"
#include "poppler-page.h"
using namespace std;
int main()
{
poppler::document *doc = poppler::document::load_from_file("./CMI2APIDocV1.4.pdf");
const int pagesNbr = doc->pages();
cout << "page count: " << pagesNbr << endl;
for (int i = 0; i < pagesNbr; ++i)
cout << doc->create_page(i)->text().to_latin1().c_str() << endl;
}
// g++ -I/usr/include/poppler/cpp/ -c poppler.cpp
// g++ -I/usr/include/poppler/cpp poppler.o /usr/lib/x86_64-linux-gnu/libpoppler-cpp.a /usr/lib/x86_64-linux-gnu/libpoppler.a /usr/lib/x86_64-linux-gnu/liblcms2.so /usr/lib/x86_64-linux-gnu/libfontconfig.a /usr/lib/x86_64-linux-gnu/libjpeg.a /usr/lib/x86_64-linux-gnu/libfreetype.a /usr/lib/x86_64-linux-gnu/libexpat.a /usr/lib/x86_64-linux-gnu/libz.a
到目前为止,我对结果非常满意,除了纯文本中的数组和“电子表格”恢复,有时单个单元格可能跨越多行。 (如果有人知道如何避免这种情况?)
对于C++。确保包含以下依赖项(否则无法编译): Advapi32.lib;Shell32.lib;