Hen*_*ski 3 text-extraction itext
我正在使用iText 5.5.8 for Java.遵循默认的,简单的文本提取程序,即
PdfTextExtractor.getTextFromPage(reader, pageNumber)
Run Code Online (Sandbox Code Playgroud)
我惊讶地发现,在输出几次失误,特别是所有的字母d的问世为Ø秒.
那么iText中的文本提取真的如何工作呢?是某种OCR吗?
我看了看引擎盖,试图掌握它是如何TextExtractionStrategy工作的,但我想不出多少.SimpleTextExtractionStrategy例如,似乎只是确定线条和空间的存在,而这TextRenderInfo是通过调用一些提供文本解码的方法GraphicsState的font领域,这是据我可以去没有得到一个重大的偏头痛.
那么谁是我的男人?其中I类应该重写或参数我应该调整到能够告诉iText的:"嘿,你在阅读完所有d错!"
编辑:
样本PDF可以在http://www.fpozzi.com/stampastopper/download/找到,文件名是0116_LR.pdf对不起,无法共享直接链接.这是文本提取的一些基本代码
import java.io.File;
import java.io.IOException;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.parser.PdfTextExtractor;
public class Import
{
public static void importFromPdf(final File pdfFile) throws IOException
{
PdfReader reader = new PdfReader(pdfFile.getAbsolutePath());
try
{
for (int i = 1; i <= reader.getNumberOfPages(); i++)
{
System.out.println(PdfTextExtractor.getTextFromPage(reader, i));
System.out.println("----------------------------------");
}
}
catch (IOException e)
{
throw e;
}
finally
{
reader.close();
}
}
public static void main(String[] args)
{
try
{
importFromPdf(new File("0116_LR.pdf"));
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
Run Code Online (Sandbox Code Playgroud)
在@blagae和@mkl回答之后编辑
在开始使用iText之前,我尝试过从Apache PDFBox中提取文本(类似于我刚刚发现的iText的项目),但确实有同样的问题.
了解这些程序如何处理文本超出了我的奉献精神,所以我编写了一个简单的方法来从原始页面内容中提取文本,即BT和ET标记之间的任何内容.
import java.io.File;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.itextpdf.text.io.RandomAccessSourceFactory;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.RandomAccessFileOrArray;
import com.itextpdf.text.pdf.parser.ContentByteUtils;
import com.itextpdf.text.pdf.parser.PdfTextExtractor;
public class Import
{
private final static Pattern actualWordPattern = Pattern.compile("\\((.*?)\\)");
public static void importFromPdf(final File pdfFile) throws IOException
{
PdfReader reader = new PdfReader(pdfFile.getAbsolutePath());
Matcher matcher;
String line, extractedText;
boolean anyMatchFound;
try
{
for (int i = 1; i <= 16; i++)
{
byte[] contentBytes = ContentByteUtils.getContentBytesForPage(reader, i);
RandomAccessFileOrArray raf = new RandomAccessFileOrArray(new RandomAccessSourceFactory().createSource(contentBytes));
while ((line = raf.readLine()) != null && !line.equals("BT"));
extractedText = "";
while ((line = raf.readLine()) != null && !line.equals("ET"))
{
anyMatchFound = false;
matcher = actualWordPattern.matcher(line);
while (matcher.find())
{
anyMatchFound = true;
extractedText += matcher.group(1);
}
if (anyMatchFound)
extractedText += "\n";
}
System.out.println(extractedText);
System.out.println("+++++++++++++++++++++++++++");
String properlyExtractedText = PdfTextExtractor.getTextFromPage(reader, i);
System.out.println(properlyExtractedText);
System.out.println("---------------------------");
}
}
catch (IOException e)
{
throw e;
}
finally
{
reader.close();
}
}
public static void main(String[] args)
{
try
{
importFromPdf(new File("0116_LR.pdf"));
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
Run Code Online (Sandbox Code Playgroud)
至少在我的情况下,似乎字符是正确的.然而,单词甚至字母的顺序实际上是凌乱的,超级凌乱,所以这种方法也无法使用.
令我惊讶的是,到目前为止我尝试过的所有方法都是从PDF中检索文本,包括从Adobe Reader复制/粘贴,搞砸了一些东西.
我得出的结论是,获得一些体面文本提取的最可靠方法也可能是最意想不到的:一些好的OCR.我现在正在尝试:1)将pdf转换为图像(PDFBox很擅长这样做 - 甚至不用去尝试pdf-renderer)2)OCR该图像我将在几天内发布我的结果.
您的输入文档是以奇怪的(但"合法的")方式创建的.资源中有一个Unicode映射,可将任意字形映射到Unicode点.特别是,dASCII中的字符编号0x64映射到Unicode点0x6f(UTF-8)的字形,即o此字体.这本身并不是问题 - 任何PDF查看器都可以处理它 - 但它很奇怪,因为使用的所有其他字形都不是"交叉映射".例如,字符0x63映射到Unicode点0x63(即c)等.
现在因为Acrobat正确地进行了文本提取(除了空间),其他的都出错了.我们必须深入研究PDF语法:
[p, -17.9, e, -15.1, l, 1.4, l, 8.4, i, -20, m, 5.8, i, 14, st, -17.5, e, 31.2, ,, -20.1, a] TJ
<</ActualText <fffffffeffffffff00640064> >> BDC
5.102 0 Td
[d, -14.2, d] TJ
EMC
Run Code Online (Sandbox Code Playgroud)
这告诉PDF查看器p-e-l-l-i- -m-i-st-e- -a在第一行代码上打印,然后d-d在第四行打印.但是,d映射到o,这显然只是文本提取的问题.Acrobat确实正确地进行了文本提取,因为有一个内容标记/ActualText表明我们在BDC和EMC标记之间写入的内容必须解析为dd(0x64,0x64).
所以回答你的问题:iText与许多备受尊敬的观众处于同一水平,这些都忽略了/ActualText标记.除了Acrobat,它尊重它并否决ToUnicode映射.
并且要真正回答你的问题:iText目前正在研究解析/ActualText标记,但它可能需要一段时间才能进入正式版本.