PDFファイルからテキストと画像を読み上げるアルゴリズムを開発中です。私はこの目的のためにiTextのJavaを使用し、基本的に私のアルゴリズムは次のように動作します。iTextは、テキストチャンクの位置が正しくない部分を抽出します。
- ページ内のすべてのテキストチャンクの座標は、iTextを使用して抽出されます。
- 抽出された座標を使用してRectangleオブジェクトが作成されます。このステップの後、ページ内の実際のテキストチャンクを表す四角形のオブジェクトが一揃いになります。
- 矩形をpdfページの実際の列に対応する大きなテキストブロックにグループ化します。
- YからXまでのテキストブロックを注文します。
- テキストブロックに1つずつ
locationTextExtractionStrategy
を適用します。
このアプローチでは、中規模から複雑なレイアウトのPDFファイルで約80%またはそれ以上の結果が得られます。私は、PDFファイルが情報を読み込み順序で保存しないため、100%の精度を得ることはほとんど不可能であることを知っています。
ここで私の正確さを高めることができますが、問題はiTextがそれをやめさせることです。私はiTextの問題を特定しました。時々、テキストチャンクの誤った場所が抽出され、アルゴリズムが正しくない場合があります。次の画像はそのための良い例です。
あなたは、実際のPDFページで列の間には明確なギャップがあることがわかります。しかし、結果の長方形には、その隙間の間にいくつかの欠陥のある長方形が含まれているため、正しい列を特定できません。
以下は、テキストチャンクの場所を抽出するために使用するコードです。私はそれらtextSegmentsに格納された座標を見て矩形オブジェクトを作成するために、得られたtextSegments
のArrayListを使用
package com.InteliText.Extract;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.parser.ImageRenderInfo;
import com.itextpdf.text.pdf.parser.LineSegment;
import com.itextpdf.text.pdf.parser.SimpleTextExtractionStrategy;
import com.itextpdf.text.pdf.parser.TextExtractionStrategy;
import com.itextpdf.text.pdf.parser.TextRenderInfo;
import com.itextpdf.text.pdf.parser.Vector;
/*
* THIS CLASS ACT AS THE TEXT EXTRACTOR FOR THE PREPROCESSOR
*/
public class PreProcessorStrategy extends SimpleTextExtractionStrategy{
private StringBuilder result = new StringBuilder();
private ArrayList<Double> fontSizes = new ArrayList<Double>();
private ArrayList<Double> lineSpaces = new ArrayList<Double>();
private ArrayList<TextSegment> textSegments = new ArrayList<TextSegment>();
Vector previousBaseLine = null;
@Override
public void beginTextBlock() {
// TODO Auto-generated method stub
}
@Override
public void endTextBlock() {
// TODO Auto-generated method stub
}
@Override
public void renderImage(ImageRenderInfo arg0) {
// TODO Auto-generated method stub
}
@Override
public void renderText(TextRenderInfo renderInfo) {
//This code assumes that if the baseline changes then we're on a newline
Vector curBaseline = renderInfo.getBaseline().getStartPoint();
Vector topRight = renderInfo.getAscentLine().getEndPoint();
//System.out.println(renderInfo.getText()+"\t"+curBaseline.get(0)+"\t"+topRight.get(0));
if(curBaseline.get(1) < 800 && curBaseline.get(1) > 50) {
// Chunk of text as a rectangle
Rectangle rect = new Rectangle(curBaseline.get(0), curBaseline.get(1), topRight.get(0), topRight.get(1));
double curFontSize = rect.getHeight();
fontSizes.add(curFontSize);
String text = renderInfo.getText();
boolean isBullet = text.contains("•");
if(!(text.equals(" ") || text.equals(" ") || text.equals(" ")) && !isBullet) {
double endX = topRight.get(0);
if(text.endsWith(" "))
endX -= 8;
textSegments.add(new TextSegment(curBaseline.get(0),endX,curBaseline.get(1),topRight.get(1),renderInfo.getText(),curFontSize));
}
result.append(renderInfo.getText());
}
previousBaseLine = topRight;
}
@Override
public String getResultantText() {
// TODO Auto-generated method stub
return result.toString();
}
public ArrayList<TextSegment> getResultantTextSegments() {
return this.textSegments;
}
。私はこれがiTextのバグかもしれないと思う。
現在のところ、テキストチャンクの内容が空白で終わっている場合は、テキストチャンクを少し縮小しています。しかし、これは一時的な修正です。正しいテキストチャンクを縮小するので、これをやりたくありません。
この問題を回避する方法はありますか?または、私のコードで問題がある場合は、それを修正するのを手伝ってください。
操作を示すテキストが、ボックスの一部であり、列の境界線を越える後続のスペースを示すようです。 – mkl