9.2.2 重なり合う異なる文字を除外して抽出する

ExtTextSetDiffTextOmitRatio_Top

狙い・効果

文字抽出文字抽出の際に重なりあっている異なる文字を除外します。

処理の概要

文字抽出の範囲で異なる文字が重なり合っているとき、重なり具合を指定して抽出対象から除外することができます。また、重なり合った文字の色が違う場合だけ取り除くよう指定することもできます。

デザイン上で異なる文字が重なりあっていた場合などでそれらの文字も抽出を防げます。

サンプルプログラムでは、入力PDFの指定したページから文字を抽出する際に、異なる文字が指定した割合以上に重なっていると除外して抽出します。また実行時に、文字色が違う場合だけ取り除くかどうかを引数で指定します。

『PDF Tool API』の主な機能

プログラム例

package cookbook;

import java.io.BufferedWriter;
import java.io.PrintWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.charset.StandardCharsets;

import jp.co.antenna.ptl.*;

public class ExtTextSetDiffTextOmitRatio {

    // そのクラスのusageを表示する関数
    private static void printUsage() {
        System.out.println("usage: java ExtTextSetDiffTextOmitRatio"
                         + " in-pdf-file out-text-file"
                         + " page-to-extract diffText-omit-ratio"
                         + " omit-diffText-in-diffColor");
        System.out.println("diffText-omit-ratio:");
        System.out.println("異なる文字が重なり合っていた場合にどの程度重なり合っていたら除外するかを小数で指定");
        System.out.println("omit-diffText-only-diffColor:");
        System.out.println("0:重なった異なる文字の色が同じ場合も取り除く 1:重なった異なる文字の色が違う場合だけ取り除く");
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        if (args.length < 5) {
            printUsage(); // usageメッセージの表示
            return;
        }

        // コマンドライン引数の読み取り・判定
        // 出力PDFの名前はあとで渡すためにString型で保存する。
        String outputTextURI = args[1];
        int pageToExtract = Integer.parseInt(args[2]);
        float diffTextOmitRatio = Float.parseFloat(args[3]);
        boolean omitDiffTextOnlyInDiffColor = true;
        try {
            omitDiffTextOnlyInDiffColor = readBoolArgs(args[4],
                                       "omit-diffText-only-diffColorは1か0で指定してください。");
        }
        catch (IllegalArgumentException ex) {
            System.out.println(ex.getMessage());
            printUsage(); // usageメッセージの表示
            return;
        }

        try (PtlParamInput inputFile = new PtlParamInput(args[0]);
             PtlPDFDocument doc = new PtlPDFDocument()) {
            // PDFファイルをロード
            doc.load(inputFile);
            //ページ数を取得
            int wholePageNum = doc.getPageCount();
            //pageToExtractのエラー処理
            if(wholePageNum < pageToExtract) {
	...【ExtractTextSetRect.javaと同じ処理のため省略
	   ・指定したページが総ページ数より多い場合のエラー処理】...
            }

            try (PtlPages pages = doc.getPages()) {//ページコンテナの取得
                // ページコンテナが空かどうか
                if (pages.isEmpty()) {
                    System.out.println("ERROR : ページコンテナが空");
                    return;
                }

                // ページの取得(パラメータindexは0が先頭のため1を引く)
                try (PtlPage page = pages.get(pageToExtract - 1);
                     // ページコンテントの取得
                     PtlContent content = page.getContent();
                     // 文字抽出のパラメータクラス。
                     PtlParamExtractText paramExtractText = new PtlParamExtractText()) {
                    // 異なるテキストがどのぐらい重なっていたら取り除くかを指定する。
                    paramExtractText.setDifferentTextOmitRatio(diffTextOmitRatio,
                                                               omitDiffTextOnlyInDiffColor);

                    // 抽出するテキストを座標順に並べるよう指定
                    //(setSameTextOmitRatioのためには指定が必要)
                    paramExtractText.setTextType(PtlParamExtractText.TEXT_TYPE.TEXT_SORT);

                    // 文字列抽出
                    String TextFromPdf = content.extractText(paramExtractText);
                    // 文字列の出力
                    outputTextFile(outputTextURI, TextFromPdf);
                    System.out.println(TextFromPdf);
                }
            }
        }
	...【GetPDFVersion.javaと同じ処理のため省略
	   ・エラーメッセージ処理と出力】...
    }


    /**
     * テキストファイルを出力するための関数。 
     * 出力エンコードはUTF-8を指定する。
     * 特に外部からの呼び出しを想定しないためprivateとする。
     * 
     * @param outputTextURI 出力ファイルのURI。
     * @param TextFromPdf 出力したいString型変数
     */
    private static void outputTextFile(String outputTextURI, String TextFromPdf) {
	...【ExtractTextSetRect.javaと同じ処理のため省略
	   ・outputTextURIのパスにTextFromPDFの内容をUTF-8エンコーディングで出力する処理】...
    }


    /**
     * 0または1を入力されたargsにより、trueまたはfalseを返すメソッド。
     * 
     * @param args 与えられるコマンドライン引数。0または1でtrueまたはfalseを指定する。
     * @param errorMessage argsが0か1でなかった場合に出力されるエラーメッセージを指定する。
     * @return argsの数値を読み取った結果を戻す
     * @throws java.lang.IllegalArgumentException argsが0か1でなかった場合に発生。
     */
    public static boolean readBoolArgs(String args, String errorMessage)
        throws IllegalArgumentException {
	...【FixUpPDFASetSaveOption.javaと同じ処理のため省略
	   ・0または1を読み取り、boolean型のfalseまたはtrueを返す関数】...
    }
}

プログラムファイル名

ExtTextSetDiffTextOmitRatio.java

入出力操作の例

C:\samples>java cookbook.ExtTextSetDiffTextOmitRatio 
usage: java ExtTextSetDiffTextOmitRatio in-pdf-file out-text-file page-to-extract diffText-omit-ratio omit-diffText-in-diffColor
diffText-omit-ratio:
異なる文字が重なり合っていた場合にどの程度重なり合っていたら除外するかを小数で指定
omit-diffText-only-diffColor:
0:重なった異なる文字の色が同じ場合も取り除く 1:重なった異なる文字の色が違う場合だけ取り除く

C:\samples>java cookbook.ExtTextSetDiffTextOmitRatio sample_overlap_text.pdf Output_ExtTextSetDiffTextOmitRatio.txt 1 0.5 0 
Output text URI :Output_ExtTextSetDiffTextOmitRatio.txt
Overlap Test 01Overlap Test 01 Overlap Test 02Overlap Test 02 Overlap Test 03 Overlap Test 03 Overlap Test 04 Overlap Test 04 verlap T st 05オーバーラップテスト05 verlap Test 06オーバーラップテスト06オーバーラップテスト07 Overlap Test 07オーバーラップテスト08 Overlap Test 08オvーerバlapーTラsッtプ09テスト09オvーerバlapーTラesッtプ10テスト10オーバーラップテスト11 Overlap Test 11オーバーラップテスト12 Overlap Test 12
-- 完了 --

この操作例では入力PDFのうち異なるテキストが重なり合っている部分を除外して文字を抽出しています。図9.19に2か所ある点線部分はそれぞれ抽出される際に除外が発生したPDF部分です。文字の色について、上の濃い(赤)点線枠は両方違う色、下の薄い(水)色点線枠はどちらも同じ色ですが、ともに他の文字列よりも重なり合った割合が大きかったため除外対象になりました。

5-9-2-2_ExtTextSetDiffTextOmitRatio_06

図9.19 入力PDFの異なる文字が重なり合った部分。文字色が異なる部分(濃い点線)と同じ部分(薄い点線)がある

色が異なりながら重なっていた部分(濃い点線枠)の抽出結果です。(図9.20)

「Overlap Test 05」、「Overlap Test 06」が大きく重なっています。特に重なっている文字「O」や「e」などが抽出除外されています。

比較として、テキストが重なった部分を除外しなかった場合の抽出例の一部も並べておきます。(図9.21)

5-9-2-2_ExtTextSetDiffTextOmitRatio_02

図9.20 操作例のうち除外された文字が含まれていた部分(抜粋)

5-9-2-2_ExtTextSetDiffTextOmitRatio_03

図9.21 異なるテキストが重なった部分を除外しなかった場合の同じ箇所。「O」や「e」は除外されていない
applyAtDifferentColor()をtrueに指定した場合

applyAtDifferentColor()をtrueにすると、抽出するテキストの文字がどれだけ重なっていても『同じ色であった場合』は除外対象ではなくなります。

入力PDFの拡大図(図9.19)で薄い点線で示した部分「Overlap Test 09」、「Overlap Test 10」に注目してみます。ここは「除外されるほど大きく重なった部分」で、且つ「同じ色で重なり合った部分」です。

操作例ではapplyAtDifferentColor()がfalseで指定されているため、『テスト09』と『オ』の間の「O」をはじめ、「Overlap Test 09」の「O」と「e」、「Overlap Test 10」の「O」が除外されています(図9.22)。ただし、同じ色の重なり合った部分ではテキストは上の段と混ざって抽出されます。

5-9-2-2_ExtTextSetDiffTextOmitRatio_04

図9.22 applyAtDifferentColor( )をfalseで指定した場合の操作例(抜粋)

これをapplyAtDifferentColor()をtrueに指定した操作例(下)と比較します。

applyAtDifferentColor()をtrueに指定した入力操作例

C:\samples>java cookbook.ExtTextSetDiffTextOmitRatio sample_overlap_text.pdf Output_ExtTextSetDiffTextOmitRatio_onlyDiffColor.txt 1 0.5 1 
Output text URI :Output_ExtTextSetDiffTextOmitRatio_onlyDiffColor.txt
Overlap Test 01Overlap Test 01 Overlap Test 02Overlap Test 02 Overlap Test 03 Overlap Test 03 Overlap Test 04 Overlap Test 04 verlap T st 05オーバーラップテスト05 verlap Test 06オーバーラップテスト06オーバーラップテスト07 Overlap Test 07オーバーラップテスト08 Overlap Test 08 OオvーerバlapーTラesッtプ09テスト09 OオvーerバlapーTラesッtプ10テスト10オーバーラップテスト11 Overlap Test 11オーバーラップテスト12 Overlap Test 12
-- 完了 --

「Overlap Test 09」、「Overlap Test 10」のテキストは、順番こそバラバラですがすべて抽出されています。具体的には、『テスト09』と『オ』の間に「O」があるほか、その他の「O」と「e」も含まれていることが確認できます。

5-9-2-2_ExtTextSetDiffTextOmitRatio_05

図9.23 applyAtDifferentColorをtrueに指定した場合の操作例の一部