LoginSignup
3

posted at

updated at

Tesseract OCRをvcpkgでインストールしてdllをRustで使う

Rust から Tesseract OCR(のライブラリ)を呼び出そうと色々やっていました。
ひとまず動くようになったので備忘録としてあげておきます。
vcpkg でインストールした DLL を Rust で使う、という場合にも使えると思います。

vcpkg をインストールする

GitHubの説明に則ってインストールします。
https://github.com/microsoft/vcpkg

Tesseract OCRライブラリをインストールする

以下コマンドでインストールします。
アニメ一本分くらいは時間かかります。
./vcpkg install tesseract:x64-windows

依存関係のあるパッケージも一緒にインストールしてくれますが、足りない場合は以下を実行してみてください。

./vcpkg install leptonica:x64-windows

Rust プロジェクトで読み込む

tesseract クレートを利用しました。
https://crates.io/crates/tesseract

Cargo.toml に以下を追記してビルドします。
tesseract = "0.12.0"

main.rs は最低限の記述にします。

main.rs
let text = tesseract::ocr("test.png", "jpn").unwrap();
println!("Tesseract: {}", text);

lib をプロジェクトのルートに設置する

vcpkg でインストールした .lib ファイルを Rust プロジェクトのルートフォルダに配置します。
lib ファイルは vcpkg\installed\x64-windows\lib 以下にあります。
tesseract のビルドに必要なファイルは以下のようです。

  • leptonica-1.82.0.lib
  • libcrypto.lib
  • libcurl.lib
  • tesseract52.lib

設置したらビルドしてみます。

> cargo build

エラーが出なければひとまずOKです。
ただし、ビルドは通っても cargo run すると DLL が足らないと怒られます。
error: process didn't exit successfully: target\debug\tesseract_rust.exe (exit code: 0xc0000135, STATUS_DLL_NOT_FOUND)

実行に必要な DLL を設置する

DLL はプロジェクトのルートではなく、exe と同じパスに設置する必要があります。
target\debug\ 以下に DLL を設置します。

lib ファイルとは違い、関連する DLL が全て必要です。
vcpkg\installed\x64-windows\tools\tesseract\ 以下にある DLL を全て target\debug\ 以下にコピーします。

動かしてみます。

> cargo run

言語ファイルが無いと言われます。
GitHub から jpn.traineddata を DL してプロジェクトのルートフォルダに設置します。
https://github.com/tesseract-ocr/tessdata

これで動作するようになりました。

build.rs でビルドを自動化する

ビルドや実行の度に関連ファイルを設置するのは面倒なので、build.rs を書いて自動化してみました。

build.rs
fn main() {
    let project_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
    println!("cargo:rustc-link-search=native={}\\lib", project_dir);

    let target_path = std::path::Path::new(&project_dir).join("target");

    if target_path.exists() {
        let debug_path = target_path.join("debug");
        let release_path = target_path.join("release");
        let dll_files = std::fs::read_dir(std::path::Path::new(&(project_dir + "\\dll"))).unwrap()
            .map(|res| res.map(|e| e.path()))
            .collect::<Result<Vec<_>, std::io::Error>>().unwrap();
        
        for path in dll_files {
            if debug_path.exists() {
                std::fs::copy(&path, debug_path.join(&path.file_name().unwrap())).unwrap();
            }
            if release_path.exists() {
                std::fs::copy(&path, release_path.join(&path.file_name().unwrap())).unwrap();
            }
        }
    }
}

今回は cargo:rustc-link-search=native= を指定して、プロジェクトルート以下の lib フォルダを参照するように設定しています。
vcpkg\installed\x64-windows\lib をフルパスで指定しても問題ないと思います。

更に、targetフォルダがある場合に dll フォルダ以下の DLL ファイルを全て debug、release フォルダにコピーするように設定しています。
こちらも、DLLフォルダはフルパスで vcpkd 以下を指定してもいいと思います。

GitHub にプロジェクトがありますので、必要な方はどうぞ。
https://github.com/sou1ka/tesseract_rust

Rustのビルド時にC++のソースも一緒にビルドしてFFIする方法もできるとは思いますが、Tesseract の構成が中々重たいので今回はvcpkg経由で試してみました。

参考

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
What you can do with signing up
3