Windows環境でのtesseract-ocrの導入とOCR環境の構築

# はじめに
前回までで、Linux環境でのPDFのOCR、dockerによるFess+Elasticsearch、nginxの導入を
記載しましたが、Windowsについても部分的に検証しましたので、検証した範囲の環境構築手順を
まとめたいと思います。

Windows環境では、docker周りの構築ができなかったので、OCR環境の構築のみを記載致します。

# 環境構築のための資材
### Tesseract-OCR
主役ですね。OCR機能を実装する箇所です。

[GitHubのtesseractのページ](https://github.com/tesseract-ocr/tesseract/wiki)からダウンロードしました。
いくつかのバージョンがありますが、バージョンによる差異は検証できていませんので、気になる方は
リリースノートを読んでください。
今回の導入時に1点だけ注意点がありました。

__3.05以前のバージョンだと、PDFにパスワードを設定して作成することができません。__

よく考えずになんとなくで、はじめに3.02をインストールしてしまい、ハマりました…
なので、3.05以上のバージョンを利用して頂くことをお勧め致します。

### Poppler
[Poppler for Windows](http://blog.alivate.com.au/poppler-windows/)をこちらからダウンロードしました。
こちらはインストーラではなく、アーカイブで提供されています。32bit版のみです。
展開して適当なフォルダに配置してあげてください。

### PDFtk
[こちら](https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/)からダウンロードしました。
PDFtk Freeのほうを使用しています。
最新版は2.02のようです。(2019年6月17日現在）
こちらはインストーラタイプなので、GUIからインストールしました。

# 環境変数の追加
インストーラによっては、自動でPathに追加されるという情報もあったのですが、
どうも自動では設定されていなそうなので、以下のパスを環境変数のPATHに
追加しました。

|パッケージ|パス|
|:-:|:-:|
|Poppler|C:\poppler\bin|
|Tesseract-OCR|C:\Program Files (x86)\Tesseract-OCR|
|PDFtk|C:\Program Files (x86)\PDFtk\bin|

PopplerはC:\Popplerに展開、Tesseract-OCRは4.0の32bit版をなぜか使用してしまったので
上記のようなパスを追加しています。
インストールした環境によってここのパスは変わってきますので、環境に合わせて設定してください。

# Tesseract-OCRの言語データの確認
Linux環境でもよくあったのですが、インストール初期状態では言語ファイルが見えなかったり
日本語言語ファイルがインストールされていないことがあります。
その場合は、*C:\[Tesseract-OCRインストールパス]\tessdata* を確認し、

* jpn.traineddata
* osd.traineddata

が存在するか確認してください。
ない場合は、[tessdataリポジトリ](https://github.com/tesseract-ocr/tessdata_best)から適宜ダウンロードしてください。
osd.traineddataはご利用のTesseract-OCRのバージョンに合わせてダウンロードしてください。
ダウンロードしたtraineddataをtessdataフォルダに保存して、tesseractを実行してエラーが出なければ
言語データのインストールは完了です。

# 自動OCRスクリプト
上記環境が出来上がれば、あとはスクリプトを作って自動化です。
一つ一つ変換するのは手間なので、フォルダ内のPDFファイルを自動でテキスト埋め込み型PDFに変換する
スクリプトを以前作ったLinuxのシェルをベースに作成してみました。

```powershell:pdfconvert.ps1
# 引数チェック
if ( $Args.Length -eq 0 ) {
$Alert = @'
usage : > pdfconvert.ps1 [対象フォルダ] [pdfパスワード(オプション)]
※[対象フォルダ]は必須
[pdfパスワード]を指定しない場合、作成したPDFにパスワードは設定されません.
終了します.
'@
Write-Host $Alert
Exit 1
}

# 引数に指定したディレクトリが存在しない場合は処理を中止する
if (!(Test-Path $Args[0])) {
$Alert = @'
指定したフォルダが存在しません.
終了します.
'@
Write-Host $Alert
Exit 1
}

# PDFパスワードを読み込む
if ( $Args[1] -ne $null ) {
$PWDTXT = $Args[1]
} else {
$PWDTXT = 0
}

# PDFファイルのリスト化
$LIST = Get-ChildItem -Recurse $Args[0] | ? { ! $_.PSIsContainer } | % { $_.FullName }

### リストをループに読み込み ###
foreach($TARGET in $LIST){

# 拡張子を除いたファイル名を抽出
$FILENAME = (Split-Path -Leaf $TARGET).Replace(".pdf","")

# ディレクトリ名を抽出
$DIRNAME = Split-Path $TARGET

# パスワード付きPDFかをチェック
$PDFSTAT = pdfinfo $TARGET | Select-String "Encrypted" | %{ $_ -split " "}

# 暗号化状態と印刷可否をチェック
if ($PDFSTAT[6] -eq "yes"){
$PRINTABLE = $PDFSTAT[7].Split(":")[1]
} else {
$PRINTABLE = "NoEnc"
}

# 画像保存フォルダの作成
$TMPDIR = $TARGET + ".d"
New-Item $TMPDIR -ItemType Directory

# 画像変換処理実行 
pdftoppm -png -r 200 $TARGET $TMPDIR/page

# 画像変換したPNGファイル一覧を取得
$PNGLIST = (Get-ChildItem -Recurse $TMPDIR | ? { ! $_.PSIsContainer } | % { $_.FullName }).Replace(".png","")

# 文字抽出したPDFを作成
foreach($PNG in $PNGLIST) {
$PNGFILE = $PNG + ".png"
tesseract $PNGFILE $PNG -l eng+jpn pdf
}

### 作成したPDFを1ファイルにまとめる
# パスワードが設定されていない場合以外の処理
if ($PRINTABLE -ne "NoEnc") {
# 引数のパスワードが指定されていない場合以外の処理
if ($PWDTXT -ne 0) {
# 印刷可能な場合の処理
if ($PRINTABLE -eq "yes") {
pdftk $TMPDIR\*.pdf output $DIRNAME\$FILENAME.pdf owner_pw $PWDTXT allow printing
# 印刷不可の場合の処理
} elseif ($PRINTABLE -eq "no") {
pdftk $TMPDIR\*.pdf output $DIRNAME\$FILENAME.pdf owner_pw $PWDTXT
}
# 引数のパスワードが指定されていない場合の処理
} else {
pdftk $TMPDIR\*.pdf output $DIRNAME\$FILENAME.pdf
}
# パスワードが設定されていない場合の処理
} else {
pdftk $TMPDIR\*.pdf output $DIRNAME\$FILENAME.pdf
}
# 一時フォルダの削除
Remove-Item $TMPDIR -Recurse
}
```

シェルとやっていることはほぼ変わらないのですが、Powershellにはxargsのように並列実行する
機能がないので、一番時間のかかるtesseractコマンドが1処理ずつしか実行されません。
xargsを利用すると並列で実行できるので、CPUコア数に応じてチューニング可能です。
その点、変換処理に関してはWindowsのほうが遅くなると思われます。
並列実行する機能がありましたらどなたか教えてください…

# 最後に
今回全文検索とOCRができるサーバの導入を検討し、WindowsとLinuxを比較検討致しましたが
実際大量変換が必要となった場合のことと、dockerの導入のしやすさを考えた結果、
Linuxでの導入を進めていこうと考えております。
大量のPDFのテキスト起こしが必要になった場合に、ただでさえ時間がかかる処理を
スクリプト側が巻き取れないPowershellで実装するのは後々後悔しそうだったので
xargsの並列実行の点とdockerの検証が済んでいるという点でLinuxとなりました。
Windowsも検証環境があればもう少し突っ込んだ検証がしたかったんですがね…

どいうことで、PDFのOCR関連の記事ストックがだいたい捌けたので、これで全文検索、OCR関連の
記事は終了です。

次は、docker周りで備忘録的に残したくなる内容が出てきたら書こうかな。