1. 从PDF中精准提取文本:不只是search()
上次我们聊了怎么用Poppler-Qt6把PDF文件“打开”,拿到页面对象。今天咱们深入一步,聊聊怎么把PDF里的文字“抠”出来。很多朋友第一反应就是用Poppler::Page的search()方法,这没错,它能帮你找到特定关键词的位置。但如果你想把一整页、甚至整个文档的文字都提取出来,做成可搜索的数据库,或者进行文本分析,search()就显得力不从心了。
Poppler-Qt6提供了更强大的文本提取能力,核心是Poppler::Page的text()方法。这个方法听起来简单,用起来却有不少门道。直接调用page->text(),它会返回一个QString,里面包含了页面上的所有文本。但你会发现,有时候提取出来的文字顺序是乱的,或者段落结构完全丢失了。这是因为PDF本身是一种“所见即所得”的格式,它记录的是每个字符在页面上的精确坐标,而不是像HTML或TXT那样有明确的段落和行结构。
所以,直接调用text()只是第一步。为了得到结构更清晰、更接近阅读顺序的文本,我们需要用到Poppler::Page的另一个方法:textList()。它返回一个QList<Poppler::TextBox*>,也就是一个文本框的列表。每个TextBox对象不仅包含了文本片段(QString text),还包含了这个文本片段所在的矩形区域(QRectF boundingBox)。有了坐标信息,我们就可以通过算法(比如按Y坐标从上到下、同Y坐标时按X坐标从左到右排序)来重建文本的阅读顺序。
这里有个我踩过的坑:textList()返回的文本框,有时候一个单词会被拆成好几个TextBox,特别是那种用了复杂字体或者有特殊格式的单词。为了解决这个问题,我通常会在排序后,对相邻的TextBox进行合并判断。如果两个框在水平方向上距离很近(比如小于一个字符的平均宽度),并且它们的Y坐标基本对齐,我就会把它们合并成一个文本块。下面是一段示例代码,展示了如何提取并初步整理一页的文本:
#include <poppler-qt6.h>
#include <QList>
#include <algorithm>
QString extractStructuredText(Poppler::Page* page) {
if (!page) return QString();
// 获取所有文本框
QList<Poppler::TextBox*> textBoxes = page->textList();
if (textBoxes.isEmpty()) return QString();
// 按位置排序:先按顶部Y坐标,再按左侧X坐标
std::sort(textBoxes.begin(), textBoxes.end(),
[](Poppler::TextBox* a, Poppler::TextBox* b) {
QRectF rectA = a->boundingBox();
QRectF rectB = b->boundingBox();
// 允许一定的Y坐标容差,视为同一行
const qreal lineTolerance = rectA.height() * 0.5;
if (qAbs(rectA.top() - rectB.top()) < lineTolerance) {
return rectA.left() < rectB.left();
}
return rectA.top() < rectB.top();
});
QString result;
QRectF prevBox;
for (Poppler::TextBox* box : textBoxes) {
QRectF currentBox = box->boundingBox();
// 判断是否需要换行或添加空格
if (!prevBox.isNull()) {
// 如果当前框和上一个框的Y坐标差距较大,说明换行了
if (currentBox.top() > prevBox.bottom() + prevBox.height() * 0.3) {
result += "\n";
}
// 如果当前框离上一个框有较大水平间隙,可能是一个单词结束或新段落,加空格
else if (currentBox.left() > prevBox.right() + prevBox.width() * 0.2) {
result += " ";
}
// 对于距离很近的框(可能是同一个单词被拆分),直接拼接

&spm=1001.2101.3001.5002&articleId=151145971&d=1&t=3&u=6826a14578c14e13a3bb7c2ab3af5f7b)
327

被折叠的 条评论
为什么被折叠?



