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

时间:2015-05-12 09:16:34

标签: objective-c pdf text stream file-format

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

Apple文档显示了一个回调示例:

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文档似乎并没有帮助像我这样的中低级程序员理解下一步:除了识别文本块(可能是在BT和BE回调之间?)之外,还有几步在回调期间/之内/之外需要/行来将识别的文本块捕获到NSString中?

非常感谢。

1 个答案:

答案 0 :(得分:0)

您应该做的第一件事是下载PDF参考。这些天是ISO标准,但您可以下载包含Adobe副本的Acrobat SDK(http://www.adobe.com/devnet/acrobat.html),也可以为您提供服务。

阅读第9章。它将教你,一方面你需要理解文本操作符(Tj,',“,TJ),另一方面你需要理解字体和编码。

文本运算符是您可以拦截的操作符,可以将“字符串”添加到PDF文档中;虽然所有文本操作符必须出现在BT和ET块之间,但我认为拦截这些BT和ET块并不会对你有太多帮助。

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

其他一些要点:

  • 不要假设BT和ET对应于实际的文本块或段落,因为您可能会从InDesign或Word等应用程序中知道它。一个文本块可能包含整个页面或单个字符(或没有任何内容)。

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

不是一项小任务:)

查看示例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时,挑战将是哪个文本属于哪个表格单元格,其中行和列结束等...

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

相关问题