TeX Alchemist Online

TeX のこと,フォントのこと,Mac のこと

macOS のデフォルト状態でコマンドラインからOCR処理を行う

macOS 12 Monterey では,OSビルトインでのOCR機能が搭載されました。Preview.app で,画像やスキャンPDF(中身がスキャン画像のPDF)に対して,ただマウスでドラッグするだけで,中身の文字を認識して選択し,コピーできるようになっています。さらに,macOS 13 Ventura では,それが日本語にも対応しました。

たとえば,(今や入手困難となってしまった)The TeXbook のアスキーによる日本語版をスキャンしたものを Preview.app で開くと,何もしなくても,文字選択できます。

これをコピーして他のエディタにペーストすると,

TEXの名称で気をつけなければならないことがほかにもある。Eの文字が不揃いになっていることだ。Eの文字を少し下げてあるのは、TeXが組版のためのシステムであることを印象づけるためであり、またほかのシステムの名称と区別するためでもある。

と,驚くほど完璧に日本語の文字を認識できていることが分かります。

すると,このOCRエンジンを Preview.app の外側からも使えないか? という欲が湧いてきます。特に,コマンドラインから使えれば,リダイレクト・パイプなどを用いて他のUNIXコマンドと連携したテキスト処理も可能となります。

それに対する一つのアイデアは次のツイートにありました。

ただし,この方法の場合,「事前にショートカットアプリでショートカットを用意しておかなければならない」という準備作業が必要となります。それだと,macOSのデフォルト状態(Macを購入した直後の状態)では動かないので,広く一般に配布するにはやや不向きです。

そこでここでは,次の条件を満たすシェルスクリプトを作ることを目指します。

要件

  • macOS のデフォルト状態で動作する。ユーザに対して,事前に何らかのツールをインストールしておくなどの準備を要求しない。
  • コマンドラインから使えるシェルスクリプトとする。
  • 入力として,PDF および JPEG/PNG などの画像ファイルの両方を受け入れる。
  • OCR認識結果は標準出力にプレーンテキストとして出力する。
  • OCR認識時に,英語として認識するか,日本語を優先して認識するかを,オプションで切り替えられる。

実装のアイデア

macOS のOCRエンジンは,Vision フレームワークというAPI群で提供されています。これを自作プログラムから呼び出せばよいのですが,Swift や Objective-C のコードとして書くと,どうしても一度 clang でコンパイルする必要があり,シェルスクリプトとしては使えません*1。そこで,AppleScriptObjC のコードとして書き,それを /usr/bin/osascript の引数として与えるのです。

いきなり完成形のシェルスクリプトを書くのは大変なので,まずは最も書きやすい Swift で Vision フレームワークを呼び出すコードを書いておいて,それを

Swift → Objective-C → AppleScriptObjC → シェルスクリプト

と次々に書き換えてゆきます。

この手法は,以前PDFの結合やQRコードの生成にも用いました。

doratex.hatenablog.jp

doratex.hatenablog.jp

完成形のシェルスクリプト

使い方

$ ./ocr.sh input1.pdf input2.jpg input3.png

のように引数に1つまたは複数のPDFや画像ファイルを指定すると,それらに対してOCR処理を実施し,認識結果を標準出力に出力します。

オプション

  • --lang ja / --lang en :日本語優先認識モード,英語のみ認識モードを切り替えます。対象画像に含まれる文字の言語に応じて切り替えてください。(デフォルト:ja
  • --dpi <VALUE>:PDFに対してOCR処理を実施するときは,事前にビットマップ画像化処理をかけてからOCRエンジンに投げます。そのときのDPI値を指定します。数値が大きいほど画像が精細になり認識精度が上がりますが,その分速度が落ちます。(デフォルト:200

変換元コード

何かの参考になるかもしれないので,最終的にシェルスクリプトに変換するまでに書いた,

  1. Swift
  2. Objective-C
  3. AppleScriptObjC

のコードも公開しておきます。

追記

この記事を公開したところ反響があり,有り難いことに,拙作の ocr.sh のフォークバージョンを作ってくださった方がいらっしゃいました。

Javascript (JXA) で書くと,AppleScriptObjC よりは Swift に近くて,読みやすいですね。

*1:shebang に #!/usr/bin/swift を付けて Swift コードをシェルスクリプト化する方法もありますが,実行環境に Xcode Command Line Tools がインストールされている必要があり,「デフォルト状態で動作する」という要件を満たしません。