我试图读取一个流,并希望为每个String获取准确的位置(坐标)
int size = reader.getXrefSize();
for (int i = 0; i < size; ++i)
{
PdfObject pdfObject = reader.getPdfObject(i);
if ((pdfObject == null) || !pdfObject.isStream())
continue;
PdfStream stream = (PdfStream) pdfObject;
PdfObject obj = stream.get(PdfName.FILTER);
if ((obj != null) && obj.toString().equals(PdfName.FLATEDECODE.toString()))
{
byte[] codedText = PdfReader.getStreamBytesRaw((PRStream) stream);
byte[] text = PdfReader.FlateDecode(codedText);
FileOutputStream o = new FileOutputStream(new File("/home..../Text" + i + ".txt"));
o.write(text);
o.flush();
o.close();
}
}
我实际上得到了像
这样的位置......
BT
70.9 800.9 Td /F1 14 Tf <01> Tj
10.1 0 Td <02> Tj
9.3 0 Td <03> Tj
3.9 0 Td <01> Tj
10.1 0 Td <0405> Tj
18.7 0 Td <060607> Tj
21 0 Td <08090A07> Tj
24.9 0 Td <05> Tj
10.1 0 Td <0B0C0D> Tj
28.8 0 Td <0E> Tj
3.8 0 Td <0F> Tj
8.6 0 Td <090B1007> Tj
29.5 0 Td <0B11> Tj
16.4 0 Td <12> Tj
7.8 0 Td <1307> Tj
12.4 0 Td <14> Tj
7.8 0 Td <07> Tj
3.9 0 Td <15> Tj
7.8 0 Td <16> Tj
7.8 0 Td <07> Tj
3.9 0 Td <17> Tj
10.8 0 Td <0D> Tj
7.8 0 Td <18> Tj
10.9 0 Td <19> Tj
ET
.....
但我不知道哪个字符串适合哪个位置 另一方面,在Itext中我可以用
获得纯文本PdfReader reader = new PdfReader(new FileInputStream("/home/....xxx.pdf"));
PdfTextExtractor extract = new PdfTextExtractor(reader);
但当然没有任何立场......
那么我怎样才能得到每个文本的确切位置(字符串,字符,...)?
答案 0 :(得分:7)
作为基座和David van Driessche在答案中已经指出,从PDF文件中提取文本并非易事。幸运的是,iText解析器包中的类为您完成了大部分繁重工作。您已经从该包中找到至少一个类PdfTextExtractor,
,但如果您只对页面的纯文本感兴趣,则此类本质上是一个便利实用程序,用于使用iText的解析器功能。在你的情况下,你必须更强烈地查看该包中的类。
使用iText获取有关文本提取主题的信息的起点是iText in Action — 2nd Edition的第15.3节解析PDF ,特别是样本ParsingHelloWorld.java的方法extractText
}}:
public void extractText(String src, String dest) throws IOException
{
PrintWriter out = new PrintWriter(new FileOutputStream(dest));
PdfReader reader = new PdfReader(src);
RenderListener listener = new MyTextRenderListener(out);
PdfContentStreamProcessor processor = new PdfContentStreamProcessor(listener);
PdfDictionary pageDic = reader.getPageN(1);
PdfDictionary resourcesDic = pageDic.getAsDict(PdfName.RESOURCES);
processor.processContent(ContentByteUtils.getContentBytesForPage(reader, 1), resourcesDic);
out.flush();
out.close();
}
使用RenderListener
实施MyTextRenderListener.java:
public class MyTextRenderListener implements RenderListener
{
[...]
/**
* @see RenderListener#renderText(TextRenderInfo)
*/
public void renderText(TextRenderInfo renderInfo) {
out.print("<");
out.print(renderInfo.getText());
out.print(">");
}
}
虽然此RenderListener
实现仅输出文本,但它检查的TextRenderInfo对象提供了更多信息:
public LineSegment getBaseline(); // the baseline for the text (i.e. the line that the text 'sits' on)
public LineSegment getAscentLine(); // the ascentline for the text (i.e. the line that represents the topmost extent that a string of the current font could have)
public LineSegment getDescentLine(); // the descentline for the text (i.e. the line that represents the bottom most extent that a string of the current font could have)
public float getRise() ; // the rise which represents how far above the nominal baseline the text should be rendered
public String getText(); // the text to render
public int getTextRenderMode(); // the text render mode
public DocumentFont getFont(); // the font
public float getSingleSpaceWidth(); // the width, in user space units, of a single space character in the current font
public List<TextRenderInfo> getCharacterRenderInfos(); // details useful if a listener needs access to the position of each individual glyph in the text render operation
因此,如果RenderListener
除了检查getText()
的文字外,还考虑getBaseline()
甚至getAscentLine()
和getDescentLine().
,那么您拥有所有坐标可能需要。
PS: ParsingHelloWorld.extractText()
PdfReaderContentParser中的代码有一个包装类,它允许您只需编写以下内容PdfReader reader,
{{ {1}}和int page,
RenderListener renderListener:
答案 1 :(得分:3)
如果您正在尝试进行文本提取,您应该意识到这绝对是一个非常重要的过程。您至少必须实现RPN计算机来运行代码并累积转换并执行所有文本运算符。您需要解释当前页面资源集中的字体指标,您可能需要了解文本编码。
当我使用Acrobat 1.0时,我负责“查找...”命令,其中包含您的问题作为子集。凭借更丰富的工具和更多的专业知识,需要几个月的时间才能做到正确。
答案 2 :(得分:1)
如果您想了解Tj运算符的字节,请查看PDF规范: http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/PDF32000_2008.pdf
更具体地说 - 请参阅第9.4.3节。要解释该部分 - 必须在用于绘制文本的字体中查找每个字节或多个字节的潜在序列(在您的示例中,字体标识为/ F1)。通过查找,您将找到此代码所指的实际字符。
另请注意,您在此处看到这些文字命令的顺序可能根本不会反映自然阅读顺序,因此您必须根据您找到的位置找出实际上这些字符的正确顺序是
另请注意,您的PDF文件可能不包含空格。由于只需将下一个字符稍微向右移动就可以“伪造”空间,因此某些PDF生成器会省略空格。但是找到坐标中的间隙可能不是一个单词突破。例如,它也可能是列的结尾。
这真的非常非常困难 - 特别是如果你想在通用PDF文件上做这件事(而不是只有少数你知道总是来自同一来源的布局)。我很久以前就为一个名为PitStop Pro的产品编写了一个PDF文本编辑器,它仍然存在(不再隶属于它),这是一个非常难的问题。
如果这是一个选项,请尝试使用现有的库或工具。这种图书馆或工具当然有商业选择;我对开源/免费库不太熟悉,所以我不能对此发表评论。