1.2.4 検索オプションの指定:同一行とみなす文字の重なり

1-2-第4項検索オプションの指定:同一行とみなす文字の重なり

狙い・効果

検索対象テキストを座標でソート指定した際に、同一行とみなす文字の重なり同一行とみなす文字と文字の縦方向の重なり割合を指定します。

処理の概要

検索対象テキストを座標でソート指定した際に、同一行とみなす文字と文字の縦方向の重なり割合を指定します。この数値は隣り合う文字の高さのうち何割が重なっていれば同じ行とみなすかを表します。例えば、デフォルト値0.7の場合は隣り合う文字の高さのうち7割が重なっていれば同じ行とみなされて文字検索が行われます。検索対象テキストを座標でソート指定する方法については1.2.3 検索オプションの指定:取得順序を参照してください。

PDF Tool APIの主な機能

PtlParamSearchText.APIsetOverlapAsLine(float overlap): 文字と文字がどれだけ重なっていると同じ行とみなすかを設定

この設定は検索対象テキストを座標でソート指定した場合にのみ有効です。数値は0.0より大きく1.0より小さい値で指定してください。

プログラム例

package cookbook;

import jp.co.antenna.ptl.*;

public class SearchTextSetOverlap {
    static final int NUM_OF_ARG_BEFORE_TEXT = 3;

    // そのクラスのusageを表示する関数
    private static void printUsage(){
        System.out.println("usage: java SearchTextSetOverlap in-pdf-file" + 
                           " page-to-search set-overlap-as-line" +
                           " searching-text... ");
        System.out.println("set-overlap-as-line : ");
        System.out.println("ずれて書かれた文字同士を同じ行とみなす重なり具合の割合");
    }

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

        // コマンドライン引数の読み取り・判定
        int pageToSearch = Integer.parseInt(args[1]); // ページ数
        float overlapRate = Float.parseFloat(args[2]); // 同じ行とみなす重なり具合
        if((overlapRate < 0) || (1 < overlapRate)) {
            System.out.println("set-overlap-as-line は、1から0の間で指定してください。");
            printUsage(); // usageメッセージの表示
            return;
        }

        // 検索テキストの設定
        int numOfSearchingText = args.length - NUM_OF_ARG_BEFORE_TEXT; 
        String[] arrayTextsToSearch = new String[numOfSearchingText];
        for (int i = 0; i < numOfSearchingText; i++){
            arrayTextsToSearch[i] = args[i + NUM_OF_ARG_BEFORE_TEXT];
        }

        try (PtlParamInput inputFile = new PtlParamInput(args[0]);
             PtlPDFDocument doc = new PtlPDFDocument())
        {
            // PDFファイルをロード
            doc.load(inputFile);

            // ページ番号が0を指定された場合はドキュメント全体から検索。
            if(pageToSearch == 0){
                searchTextInDocumentSetTextType(doc, arrayTextsToSearch, overlapRate);
            } else {

	...【SearchText.javaと同じ処理のため省略
	 ・検索ページ番号のエラー処理】...

                // 指定ページ番号内を検索。
                searchTextInPageSetTextType(doc, arrayTextsToSearch, pageToSearch,
                                            overlapRate);
            }
        }

	...【ExtractText.javaと同じ処理のため省略
	 ・エラーメッセージ処理と出力】...

    }

    /**
     * 
     * @param doc
     * @param arrayTextsToSearch 
     */
    private static void searchTextInDocumentSetTextType(PtlPDFDocument doc,
                                                        String[] arrayTextsToSearch,
                                                        float overlapRate)
        throws PtlException {
        System.out.println("ドキュメント全体から検索します。");
        try(PtlParamSearchText paramSearchText = new PtlParamSearchText()) {
            // TEXT_TYPEの設定
            System.out.println("set-overlap-as-lineを設定するため、" +
                               "TEXT_TYPEにTEXT_SORTを指定します。" +
                               "取得したテキストを座標でソートして検索します。\n");
            paramSearchText.setTextType(PtlParamSearchText.TEXT_TYPE.TEXT_SORT);

            // setOverlapAsLineの設定
            paramSearchText.setOverlapAsLine(overlapRate);

            // 検索パラメータに対象文字列を追加
            for(String textToSearch: arrayTextsToSearch) {
                paramSearchText.appendText(textToSearch);
            }
            // 検索結果コンテナクラスに検索結果を取得し、displaySearchResultsを呼び出す
            try(PtlSearchTextResults resultsContainer = doc.searchText(paramSearchText)) {
                displaySearchResults(resultsContainer);
            }
        }

    }

    private static void searchTextInPageSetTextType(PtlPDFDocument doc,
                                                    String[] arrayTextsToSearch,
                                                    int pageToSearch,
                                                    float overlapRate)
        throws PtlException {
        System.out.println( pageToSearch +  "ページ目から検索します。");
        //ページコンテナの取得
        try (PtlPages pages = doc.getPages()) {
            // ページコンテナが空かどうか
            if (pages.isEmpty()) {
                System.out.println("ERROR : ページコンテナが空");
                return;
            }

            // ページの取得(index番号は0が先頭のため1を引く)
            try (PtlPage page = pages.get(pageToSearch - 1);
                 PtlParamSearchText paramSearchText = new PtlParamSearchText()) {
                // TEXT_TYPEの設定
                System.out.println("set-overlap-as-lineを設定するため、" +
                                   "TEXT_TYPEにTEXT_SORTを指定します。" +
                                   "取得したテキストを座標でソートして検索します。\n");
                paramSearchText.setTextType(PtlParamSearchText.TEXT_TYPE.TEXT_SORT);

                // setOverlapAsLineの設定
                paramSearchText.setOverlapAsLine(overlapRate);

                // 検索パラメータに対象文字列を追加
                for(String textToSearch: arrayTextsToSearch) {
                    paramSearchText.appendText(textToSearch);
                }
                // 検索結果コンテナクラスに検索結果を取得
                try(PtlSearchTextResults resultsContainer =
                    page.searchText(paramSearchText)) {
                    displaySearchResults(resultsContainer);
                }
            }
        }
    }

    // 検索結果を表示する関数
    private static void displaySearchResults(PtlSearchTextResults resultsContainer)
        throws PtlException {

	...【SearchText.javaと同じ処理のため省略】...

    }

// 該当テキスト検索結果の詳細コンテナ及びQuadPointを取得して表示する。
    private static void printResultQuadPoints(PtlSearchTextResultDetail resultDetail)
        throws PtlException {

	...【SearchText.javaと同じ処理のため省略】...

    }

    private static void printXYCoordinate(PtlPoint point) throws PtlException {
        System.out.println("(" + point.getX() + "," + point.getY() + "), ");
    }
}

プログラムファイル名

SearchTextSetOverlap.java

入出力操作の例

C:\samples>java cookbook.SearchTextSetOverlap 
usage: java SearchTextSetOverlap in-pdf-file page-to-search set-overlap-as-line searching-text... 
set-overlap-as-line : 
ずれて書かれた文字同士を同じ行とみなす重なり具合の割合

C:\samples>java cookbook.SearchTextSetOverlap baseline-shift-single.pdf 1 0.6 テキスト上 
1ページ目から検索します。
set-overlap-as-lineを設定するため、TEXT_TYPEにTEXT_SORTを指定します。取得したテキストを座標でソートして検索します。

検索結果 : 1件見つかりました。
searchResult No.1 : 1ページ目
searchResult keyword : テキスト上
searchResultDetail No. :1
resultDetail keyword : テキスト
該当箇所の矩形座標(x,y)はそれぞれ左下・右下・左上・右上の順に、
(74.32778,186.22668), 
(94.083336,186.22668), 
(74.32778,191.14583), 
(94.083336,191.14583), 
です。
searchResultDetail No. :2
resultDetail keyword : 上
該当箇所の矩形座標(x,y)はそれぞれ左下・右下・左上・右上の順に、
(94.083336,187.80711), 
(99.022224,187.80711), 
(94.083336,192.72626), 
(99.022224,192.72626), 
です。
-- 完了 --

1.2.4 検索オプションの指定:同一行とみなす文字の重なり(例)

baseline-shift-single.pdfには「テキスト上」という文字列が二つあります。一方は、重複度0.51、もう一方は重複度0.67になっているため重複度0.6を指定すると一方だけヒットします。