首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >iText是否支持光学字符识别?

iText是否支持光学字符识别?
EN

Stack Overflow用户
提问于 2013-05-15 21:06:17
回答 5查看 6.2K关注 0票数 3

我想问一个关于iText的问题。我在PDF文件中搜索文本时遇到问题。

我可以使用getTextfromPage()方法创建一个纯文本文件,如下面的代码示例所述:

代码语言:javascript
复制
/** The original PDF that will be parsed. */
    public static final String PREFACE = "D:/B.pdf";
    /** The resulting text file. */
    public static final String RESULT = "D:/Result.txt";
public void ParsePDF(String From, String Destination) throws IOException{

        PdfReader reader = new PdfReader(PREFACE);  
        PrintWriter out = new PrintWriter(new FileOutputStream(RESULT));              
        for (int i = 1; i <= reader.getNumberOfPages(); i++) {                          
         out.println(PdfTextExtractor.getTextFromPage(reader, i));  
        }
        out.flush();
        out.close();
        reader.close();

    }

我试图在结果文本中找到一个特定的String,如下所示:

代码语言:javascript
复制
    public void FindWords(String From) {
        try{
            String ligneLue;            
            LineNumberReader lnr=new LineNumberReader(new FileReader(RESULT));
            try{                
                while((ligneLue=lnr.readLine())!=null){
                    SearchForSVHC(ligneLue,SvhcList);
                }
            }
            finally{                
                lnr.close();
            }
        }
        catch(IOException e){
            System.out.println(e);}
        }   
    public void SearchForSVHC(String Ligne,List<String> List){
        for(String CAS :List){
            if(Ligne.contains(CAS)){
                System.out.print("Yes  "+CAS);
                break;
        }}
    }

我的问题是,我正在解析的一些PDF文件是由扫描的图像组成的,这意味着没有真正的文本,只有像素。

iText是否支持光学字符识别,并作为后续问题:是否有一种方法来确定是否由扫描的图像组成?

EN

回答 5

Stack Overflow用户

发布于 2013-05-15 21:19:27

在回答你的问题之前,我已经对它做了非常彻底的编辑。

当PDF由扫描的图像组成时,没有真正要解析的文本,只有像素看起来像文本的图像。你需要做光学字符识别才能知道在这样的扫描页面上实际写的是什么,而iText不支持光学字符识别。

关于后续问题:很难找出PDF是否包含扫描的图像。第一个泄漏是:页面中只有一个图像,没有文本。

但是:由于您对图像的性质一无所知(也许您的PDF中只包含假日照片),因此很难确定该PDF是否是一个充满扫描文本页面(即:光栅化的文本)的文档。

票数 4
EN

Stack Overflow用户

发布于 2013-05-15 21:18:30

This支持案例表明iText不支持光学字符识别。识别图像是否包含文本就像将图像传递给OCR处理器并检查结果是否有意义一样简单。

票数 1
EN

Stack Overflow用户

发布于 2019-03-25 19:14:32

它可以使用iText和Tesseract (一种google OCR实现)的组合来完成。

首先,我将在OCR引擎周围放置一个接口。这允许我稍后将其调出。

代码语言:javascript
复制
public interface IOpticalCharacterRecognitionEngine {

class OCRChunk {
    private Rectangle location;
    private String text;
    public OCRChunk(Rectangle rectangle, String text){
        this.location = rectangle;
        this.text = text;
    }
    public String getText(){ return text; }
    public Rectangle getLocation(){return location;}
}

List<OCRChunk> doOCR(BufferedImage bufferedImage);
}

这个界面本质上是说"OCR引擎返回的对象是位置(矩形)和文本的组合“

然后,我们需要创建一个ITextExtractionStrategy,它使用OCREngine将ImageRenderInfo事件转换为TextRenderInfo

代码语言:javascript
复制
public class OCRTextExtractionStrategy implements ITextExtractionStrategy {

private final ITextExtractionStrategy innerStrategy;
private final IOpticalCharacterRecognitionEngine opticalCharacterRecognitionEngine;
private final Logger logger = Logger.getLogger(OCRTextExtractionStrategy.class.getSimpleName());

public OCRTextExtractionStrategy(ITextExtractionStrategy innerStrategy, IOpticalCharacterRecognitionEngine opticalCharacterRecognitionEngine){
    this.innerStrategy = innerStrategy;
    this.opticalCharacterRecognitionEngine = opticalCharacterRecognitionEngine;
}

public String getResultantText() {
    return innerStrategy.getResultantText();
}

public void eventOccurred(IEventData iEventData, EventType eventType) {
    // handle images
    if(eventType == EventType.RENDER_IMAGE){

        // extract coordinates
        ImageRenderInfo imageRenderInfo  = (ImageRenderInfo) iEventData;
        float x = imageRenderInfo.getImageCtm().get(Matrix.I11);
        float y = imageRenderInfo.getImageCtm().get(Matrix.I22);

        // attempt to parse image
        try {
            BufferedImage bufferedImage = imageRenderInfo.getImage().getBufferedImage();
            for(IOpticalCharacterRecognitionEngine.OCRChunk chunk : opticalCharacterRecognitionEngine.doOCR(bufferedImage)){
                if(chunk.getText() != null && !chunk.getText().isEmpty()) {
                    chunk.getLocation().translate((int) x, (int) y);
                    TextRenderInfo textRenderInfo = pseudoTextRenderInfo(chunk);
                    if(textRenderInfo !=  null)
                        innerStrategy.eventOccurred( textRenderInfo, EventType.RENDER_TEXT);
                }
            }
        } catch (IOException e) { logger.severe(e.getLocalizedMessage()); }

    }
    // handle anything else
    else {
        innerStrategy.eventOccurred(iEventData, eventType);
    }
}

private TextRenderInfo pseudoTextRenderInfo(IOpticalCharacterRecognitionEngine.OCRChunk chunk){

    // dummy graphics state
    ModifiableGraphicsState mgs = new ModifiableGraphicsState();
    try {
        mgs.setFont(PdfFontFactory.createFont());
        mgs.setCtm(new Matrix(  1,0,0,
                                0,1,0,
                                0,0,1));
    } catch (IOException e) { }

    // dummy text matrix
    float x = chunk.getLocation().x;
    float y = chunk.getLocation().y;
    Matrix textMatrix = new Matrix( x, 0,0,
                                0, y, 0,
                                0,0,0);

    // return TextRenderInfo object
    return new TextRenderInfo(
            new PdfString(chunk.getText(), ""),
            mgs,
            textMatrix,
            new Stack<CanvasTag>()

    );
}

public Set<EventType> getSupportedEvents() { return null; }

}

这个类执行这种转换。坐标变换有一些神奇之处(我可能还没有完全正确)。

这项工作的繁琐工作在pseudoTextRenderInfo方法中执行,该方法将IOpticalCharacterRecognitionEngine给出的结果转换为TextRenderInfo对象。

为了让它工作,我们需要一个可修改的CanvasGraphicsState。默认的实现不是这样的,所以让我们扩展一下默认的。

代码语言:javascript
复制
class ModifiableGraphicsState extends CanvasGraphicsState{

private Matrix ctm;

public ModifiableGraphicsState(){ super(); }

public Matrix getCtm() { return ctm; }
public ModifiableGraphicsState setCtm(Matrix ctm){this.ctm = ctm; return this;};
public void updateCtm(float a, float b, float c, float d, float e, float f) { updateCtm(new Matrix(a, b, c, d, e, f)); }
public void updateCtm(Matrix newCtm) {
    ctm = newCtm.multiply(ctm);
}

}

最后,我们需要一个IOpticalCharacterRecognitionEngine的实现。这个具体的实现是使用Tesseract (如果使用Java,则为tess4j)完成的。

代码语言:javascript
复制
public class TesseractOpticalCharacterRecognitionEngine implements IOpticalCharacterRecognitionEngine {

private Tesseract tesseract;

public TesseractOpticalCharacterRecognitionEngine(File tesseractDataDirectory, String languageCode){
    tesseract = new Tesseract();

    // set data path
    if(!tesseractDataDirectory.exists())
        throw new IllegalArgumentException();
    tesseract.setDatapath(tesseractDataDirectory.getAbsolutePath());

    // set language code
    if(!new File(tesseractDataDirectory, languageCode + ".traineddata").exists())
        throw new IllegalArgumentException();
    tesseract.setLanguage(languageCode);
}

public List<OCRChunk> doOCR(BufferedImage bufferedImage) {
    List<OCRChunk> textChunkLocationList = new ArrayList<>();
    try {
        for(Rectangle rectangle : tesseract.getSegmentedRegions(bufferedImage, ITessAPI.TessPageIteratorLevel.RIL_WORD)){
            String text = tesseract.doOCR(bufferedImage, rectangle);
            textChunkLocationList.add(new OCRChunk(rectangle, text));
        }
    } catch (Exception e) { }
    return textChunkLocationList;
}
}

然后,您可以按如下方式调用代码:

代码语言:javascript
复制
// initialize tesseract
TesseractOpticalCharacterRecognitionEngine ocrEngine = new TesseractOpticalCharacterRecognitionEngine(new File("tessdata_fast"), "eng");

// create document
PdfDocument pdfDocument = new PdfDocument(new PdfReader(new File("scanned_document.pdf")));

// extract text
SimpleTextExtractionStrategy simpleTextExtractionStrategy = new SimpleTextExtractionStrategy();
OCRTextExtractionStrategy ocrTextExtractionStrategy = new OCRTextExtractionStrategy(simpleTextExtractionStrategy, ocrEngine);
    new PdfCanvasProcessor(ocrTextExtractionStrategy).processPageContent(pdfDocument.getPage(1));

// display
System.out.println(simpleTextExtractionStrategy.getResultantText());
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16565840

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档