LoginSignup
18
20

More than 5 years have passed since last update.

JavaでPDFファイルをOCR処理してみた

Last updated at Posted at 2017-12-28

始めに

PDFに含まれているイメージファイルをOCR処理するJavaのプログラムを書いてみた
当初はpythonで実装しようとしたが、使用するライブラリの依存関係が意味わからめだったので、仕方なく使い慣れたJavaで実装することにした

使用したライブラリ

工夫した点などなど

  • PDFの解析のサンプルプログラムはどれもループ使いすぎてソースが見づらかったので、自分はmapとreduceを駆使してみて書いてみたよ
  • Iteratorからstreamへの変換はもっとスマートな方法がないものだろうか・・・

ソース

PDFからイメージを取得するクラス

PDFmaker.java
package pdf;

import java.io.File;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;

public class PDFMaker {
    public static void main(String args[])throws Exception{
        //読み込むPDFファイル
        PDDocument document = PDDocument.load(new File("C:/python/img/pdf/2017h29a_sc_pm2_qs.pdf"));
        //PDFページを処理する
        Stream<PDPage>stream = StreamSupport.stream(Spliterators.spliteratorUnknownSize(
                document.getDocumentCatalog().getPages().iterator(),
                        Spliterator.ORDERED),false);

        System.out.println("start");
        Files.write(Paths.get("parse.txt"), 
                stream.map(s->exePDFpage(s)).collect(Collectors.toList()), 
                Charset.forName("MS932"),
                StandardOpenOption.CREATE);
        System.out.println("end");
    }

    //PDFのPageを処理する
    public static String exePDFpage(PDPage p){
        Stream<COSName>stream = StreamSupport.stream(Spliterators.spliteratorUnknownSize(
                p.getResources().getXObjectNames().iterator(),Spliterator.ORDERED),false);
        return stream.map(s->exeImage(s,p.getResources()))
        .reduce((s,v)->s+v).get();
    }

    //PDFのPageをJpgに変換する
    public static String exeImage(COSName n,PDResources resources){
        try{
            PDXObject xobject = resources.getXObject(n);
            if(xobject instanceof PDImageXObject){
                PDImageXObject image2 = (PDImageXObject) resources.getXObject(n);
                return PDFtoImg.extractFromPDF(image2.getImage());
            }
            return "";
        }catch(Exception e){
            e.printStackTrace();
            return "";
        }   
    }
}

イメージファイルをOCR読み込みする処理

PDFtoImg.java
package pdf;

import java.awt.image.BufferedImage;

import net.sourceforge.tess4j.ITesseract;
import net.sourceforge.tess4j.Tesseract;
import net.sourceforge.tess4j.TesseractException;

public class PDFtoImg {
    private static final String  DICTIONARY_PATH ="C:/Users/takayoshi/workspace/PDF/tessdata";
    public static String extractFromPDF(BufferedImage img) {
        ITesseract instance = new Tesseract();
        try {
            instance.setLanguage("jpn");
            instance.setDatapath(DICTIONARY_PATH);
            String result = instance.doOCR(img);
            return result;
        } catch (TesseractException ex) {
            ex.printStackTrace();
            return "";
        }
    }
}

感想

  • 情報処理技術者試験の情報処理安全確保支援士試験(SC)の問題を改正するのに大体10分~20分くらいかかる
  • 最初の1ページ目の解析結果は以下の通り
平成 29 年度 秋期
{ ニ `
情報処理女全確保支援士試験
ノ
午後 = 問題
試験時聞 ー4:30 ~ ー6:30 (2 時間)
注意事項
ー・ 試験開始及び終了は, 監督員の時計が基準です。 監督員の指示に従つてく だ さい〟
2~ 試験開始の合図がある まで, 問題冊子を開いて中を見てはいけません。
3~ 答案用紙への受験番号などの記入は, 試験開始の合図がぁってから始めてください。
4_ 問題は, 吹の表に従つて解答してください。

OCRがフリーだということを考えても、日本語でも結構いい線いっていると思う

18
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
20