使用Apache PDFBox从PDF文档中删除OCR文本

问题描述 投票:0回答:1

系统中的一些PDF文档是通过包含OCR文本进行扫描而创建的。但是,OCR没有正确执行(混合了西里尔字母和拉丁字符),虽然文档看起来像可搜索,但该信息完全不正确且无法使用。

在Adobe Acrobat Reader DC(或Google Chrome)中查看PDF文档时,它会正确显示,但在使用PDF.js呈现文档的网页上,OCR文本显示在前面,而不是扫描原始文本的图形显示。

我们的想法是通过从PDF文档中删除OCR文本来“修复”这些文档,同时保留原始文本的扫描图形表示。

为此,我使用Apache PDFBox 2.0.11检查PDF文档的内容。以下代码段打印出PDF文档中包含的整个文本,在这种情况下,整个文本与OCR文本完全相同:

PDDocument document = PDDocument.load(new File("D:/input.pdf"));
PDFTextStripper stripper = new PDFTextStripper();
stripper.setStartPage(1);
stripper.setEndPage(document.getNumberOfPages());
String sText = stripper.getText(document);
System.out.println(sText);
document.close();

然后我使用了PDFBox提供的示例类RemoveAllText,希望从PDF文档中删除OCR文本。不幸的是,它不仅删除了OCR文本,还删除了原始扫描文本的图形表示。检查PDF文档中的文本元素并将其删除的方法如下所示:

private static List<Object> createTokensWithoutText(PDContentStream contentStream) throws IOException
{
    PDFStreamParser parser = new PDFStreamParser(contentStream);
    Object token = parser.parseNextToken();
    List<Object> newTokens = new ArrayList<Object>();
    while (token != null)
    {
        if (token instanceof Operator)
        {
            Operator op = (Operator) token;
            if ("TJ".equals(op.getName()) || "Tj".equals(op.getName()) ||
                "'".equals(op.getName()) || "\"".equals(op.getName()))
            {
                // remove the one argument to this operator
                newTokens.remove(newTokens.size() - 1);

                token = parser.parseNextToken();
                continue;
            }
        }
        newTokens.add(token);
        token = parser.parseNextToken();
    }
    return newTokens;
}

我认为应该以某种方式更改此方法(仅删除文本而不删除其图形表示),但我不知道该怎么做。

这是an example of PDF document before RemoveAllText,这里是an example of PDF document after RemoveAllText

apache pdf ocr pdfbox pdf.js
1个回答
2
投票

您从PDFBox示例中复制的createTokensWithoutText代码确实存在错误。但是,该示例从扫描的PDF中删除所有文本的原因是扫描程序已经从图像中删除了字母,为它们创建了特殊字体,并使用这些字体再次将它们绘制为文本,因此该示例只是执行了它是有意义的。

Error in createTokensWithoutText

虽然显示运算符Tj,'和TJ的文本确实只有一个参数,但“有三个:

aw ac string“ - 移动到下一行并显示文本字符串,使用aw作为单词间距,ac作为字符间距(在文本状态中设置相应的参数).aw和ac应为在未缩放的文本空间中表示的数字单位。

(ISO 32000-1表109 - 文本显示操作符)

因此,如果流中存在“操作”,则createTokensWithoutText仅删除字符串参数和运算符,但保留数字参数aw和ac。这反过来会导致newTokens中以下指令的参数集无效。

How the example PDF is scanned

这里的OCR软件并不是简单地在图像中的字形前面或后面添加不可见字符来提供文本提取功能(这是一种非常常见的方法)。相反,它实际上从图像中的字形创建了特殊字体,从图像中删除了字形,并在图像前面明显地绘制了它们。

因此,剩余的图像仅包含软件与任何字形无关的一些污垢。

ad-hoc字体包含如下字形:

screenshot

如您所见,字体甚至包含同一个识别字母的多个字形,例如这里的'H'是9,13和15。

这种方法的优点是可以更轻松地操作PDF,可以编辑文本块。

不幸的是,对于你的情况,OCR软件似乎只知道拉丁字符和阿拉伯数字,特别是它似乎不知道西里尔字符。因此,它将西里尔字形分配给最相似的拉丁字符或阿拉伯数字。

这当然使文本提取毫无意义。此外,一些观看者使用一些标准字体而不是ad-hoc字体中的字形来显示指定的拉丁字符,特别是在标记文本时,并且显示的文本也没有意义。


因此,您应该再次使用OCR切换扫描或将PDF导出为图像,并仅从这些图像构建新的PDF。

© www.soinside.com 2019 - 2024. All rights reserved.