objective-c - 使用 CGPDFScanner 仅从 PDF 文件中提取文本

标签 objective-c pdf text stream file-format

有许多关于从 PDF 文件中提取简单文本的问题(有些已回答,有些未回答)。 Stackoverflow 有助于指出 PDF Adob​​e 文档在解析期间非常清楚地检测对象:即在使用 CGPDFScanner 时应该使用“BT”和“ET”PDF 引用运算符来构造回调

苹果文档显示了一个回调示例:

static void op_BT (CGPDFScannerRef s, void *info) {
    const char *name;
    if (!CGPDFScannerPopName(s, &name))
        return;
    printf("BT /%s\n", name);   
}

并且,在其他 CGPDFScanner 命令中,上述回调是通过首先创建来设置的:

myTable = CGPDFOperatorTableCreate();
CGPDFOperatorTableSetCallback (myTable, "BT", &op_BT);

到目前为止一切正常,但 Apple 文档似乎无法帮助像我这样的中低级程序员理解下一步:除了识别文本 block (大概在 BT 和 BE 回调之间?),还有几个步骤/lines are needed during/in/outside the callback to capture the identified text block into NSString?

非常感谢。

最佳答案

您应该做的第一件事是下载 PDF 引用。如今,这是一个 ISO 标准,但您可以下载 Acrobat SDK ( http://www.adobe.com/devnet/acrobat.html ),其中包含同样适用于您的 Adob​​e 副本。

阅读第 9 章。它将告诉您,一方面您需要了解文本运算符(Tj、'、"、TJ),另一方面您需要了解字体和编码。

文本运算符是您可以拦截的向 PDF 文档添加“字符串”的运算符;虽然所有文本运算符都必须出现在 BT 和 ET block 之间,但我认为单独拦截这些 BT 和 ET block 不会对您有太大帮助。

字体很重要,因为它们将定义这些运算符使用的字节如何对应于实际 (Unicode) 字符。因此,如果您想从 PDF 文件中获取字节的含义,您需要知道如何使用字体来获取该含义。

一些额外的要点:

  • 不要假设 BT 和 ET 对应于您可能从 InDesign 或 Word 等应用程序中了解到的实际文本 block 或段落。一个文本 block 可能包含整个页面或单个字符(或什么都没有)。

  • 还有一些文本状态运算符可以确定文本在页面上的显示方式。例如,有一些方法可以绘制不可见的文本;您可能希望也可能不希望提取该类型的文本。如果不这样做,您将需要支持足够多的文本状态运算符,以便您能够区分它们。

不是一个小任务:)

查看示例 PDF 后更新

因为在评论中问题被细化为指示特定类型 PDF 文件的文本提取,所以让我添加一些额外的信息。

1) 查看您引用的 PDF 文件,您将无法跳过字体/编码问题。示例 PDF 文件中的字体是子集化的,这意味着您在 PDF 页面描述中没有“明文”,而是必须通过用于获取有意义文本的字体编码进行映射的索引。

2) 提取文本是可能的,如果您查看 pdfToolbox 的以下输出(警告,我非常喜欢这个工具):

<page id="33">
    <words>
        <word txt="Senator">
            <parts>
                <part tlh="28.3481" tlv="868.534" trh="55.4455" trv="868.534" blh="28.3481" blv="859.902" brh="55.4455" brv="859.902"></part>
            </parts>
        </word>
        <word txt="House,">
            <parts>
                <part tlh="57.5305" tlv="868.534" trh="82.123" trv="868.534" blh="57.5305" blv="859.902" brh="82.123" brv="859.902"></part>
            </parts>
        </word>
        <word txt="85">
            <parts>
                <part tlh="84.208" tlv="868.534" trh="92.548" trv="868.534" blh="84.208" blv="859.902" brh="92.548" brv="859.902"></part>
                </parts>
        </word>

毫无疑问,还有其他工具可以提供类似(或更好)的结果,因此自行提取文本应该是可行的。

最大的问题是以正确的顺序找到您感兴趣的文本。我在这里使用的提取给出了每个“单词”的文本及其在页面上的位置(边界框)。当我查看表格时的 XML 时,挑战将是哪个文本属于哪个表格单元格、行和列的结束位置等...

在某种程度上,这个问题比简单地检测文本行的问题更难,因为你正在处理一个非常密集的表格(我的问题主要是一维的(将所有内容都集中在同一行上)这个问题是二维的。

关于objective-c - 使用 CGPDFScanner 仅从 PDF 文件中提取文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30186577/

相关文章:

java - 是否可以用 itext 覆盖 PDF 标题?

iOS 在 Objective-C 中登录/注销过程后更改 rootViewController

asp.net - 使用 abcpdf 下载 html 文件为 pdf

ios - 如何从另一个 ViewController 更改背景颜色?

c# - itextSharp - 合并 pdf 文件会禁用扩展阅读器权限

python - 在文本文件中存储 Python 实例属性的更好方法是什么?

c# - 我如何在 c# 或 vb.net 中向图像添加文本

javascript - 检查 HTML 标签是否可以包含文本

ios - 两个nsdates之间的时间差

ios - 如何在 sprite kit 游戏中改变重心?