miauのブログ

はてなダイアリー「miauの避難所」をはてなブログに移行しました

ScanSnapHelper(ScanSnap Manager 補助ツール)を作ってみた

前回 ScanSnap S1500 のスキャン時の動作など

(3) RAW画像の出力
(中略)
後続の処理に進むとすぐ消されてしまうファイルですが、このファイルを保存したり差し換えたりする方法については後日また書こうと思います。

と書きましたが、この「RAW画像を保存したり差し換えたりする方法」というのは、自作のツールを使うものでした。公開できる程度にまとめたので Github に上げました。

プログラムの説明は README.md にざっと書いているので、ここでは補足的な内容を書いておきます。

検証環境

Windows 7/8 上で

といった組み合わせで動作確認しています。

見た目

こんな感じです。地味です。

処理のタイミング

ScanSnap Manager(PfuSsMon.exe)では

  • (1) C:\WINDOWS\SSDriver\fi5110\fjtw32.dll 経由で ScanSnap*.raw に書き込み
  • (2) %PROGRAMFILES%\PFU\ScanSnap\Driver\PfuSsCtl.dll 経由で ScanSnap*.raw を読み込み

という動作になっていました。この (2) のタイミングで hook.bat を呼び出すため、CreateFileA

  • dwDesiredAccess が GENERIC_READ
  • lpFileName が SSRawData\ScanSnap を含む

状態で呼び出されたことを条件に hook.bat を起動しています。

ScanSnap Manager for fi(PfuSsMff.exe)では、RAW ファイルのパスは

%APPDATA%\PFU\ScanSnapManagerForFi\ScandAll PRO【0からの連番】.raw

という名称になりますが、こちらは

  • (1) C:\WINDOWS\Twain_32\Fjicube\fjictwsv.exe で書き込み
  • (2) PfuSsMff.exe で読み込み

という動作になっていました。PfuSsMff.exe を監視している限りは、うまいこと ScanSnap Manager と同一の条件で引っかけることができたので、こちらにも対応した次第です。

RAW画像の差し換えについて

サンプルスクリプト replace_images.py の説明として、

  • RAW 画像を images ディレクトリにある同名のファイルで置き換えます。
  • copy_here.py で保存した RAW 画像を再利用し、ScanSnap Manager の設定によって結果がどう変わるかを検証するのに使えます。

と書きましたが、差し換え後のファイルはどんなものでもいいわけではありません。適当な JPEG ファイルに差し換えると

イメージの処理中にエラーが発生しました。
ケーブル類を一度抜いてから、再度接続してください。

のエラーになります。%PROGRAMFILES%\PFU\ScanSnap\Driver\PfuSsCtlErr.log によると

ExtractImageFromJFIF() Failed. Error = FFFFFFFF.

だそうで、詳細は不明です。

ちゃんと確認していないのですが、ScanSnap が RAW 画像を作る際に使用しているのが LEADTOOLS なので、LEAD Command Line Image File Converter であらかじめ変換をかけてやれば RAW 画像として読み込んでくれるようでした。

LEAD Command Line Image File Converter を C:\LEADCMD にインストールしたものとして、Python Imaging Library (PIL) で作成した画像を RAW として使えるようにする例を

に make_raw_files.py として上げていますので参考にどうぞ。

ちなみにこのスクリプトは、背景の上に 4000x4000 pixel の白い正方形を描き、その四隅に赤いマークをつけるものです。これを RAW 画像として取り込むと、3997x4003 pixel となり、左は 4 pixel、上は 2 pixel が削られていました。逆に右は 1 pixel、下は 5 pixel 背景部分が残っています。実際にスキャンしたものと違って影がないので、そのあたりの調整でずれているのかもしれません。

ついでに、上の gist に上がっている pick_jpg.py は引数で渡された .pdf から .jpg を抽出するものです。生データがそのまま埋め込まれているだけなので、かなり簡単なスクリプトで抽出できちゃいます。

原稿の回転について

元々このツールを作った動機は、サンプルスクリプト rotate_for_comic.py の処理で、

  • 右綴じ・右開きの本を横向きにスキャン可能にするためのものです。
    • 実際にやってみるとクロッピングがおかしなことになったので、実用には向きません。
  • JPEG Lossless Rotator を .\jpegr_portable64 として配置した上で使う必要があります。
  • 偶数ページは左に 90 度、奇数ページは右に 90 度回転させます。

これです。

  • 原稿を横向きにして取り込む
    • スキャンする距離が短くなるので取り込みが速くなる
    • 自分で断裁した面を上に向けられるので、断裁面が多少曲がっていたり破れたりしていても問題ない
  • RAW 画像時点でロスレス回転する
    • RAW 画像は 8 の倍数 pixel になっているようなので、問題なくロスレス回転できる
  • ScanSnapHelper を起動しておくだけでよく、その後の加工の手間も要らない

ということで利点だらけなのですが、実際やってみると、クロッピングがおかしく・・・あれ?極端にクロッピングがおかしくなったりはしませんね。どうも以前検証した際に勘違いしただけっぽいです・・・。

気が向いた方は使ってみてもいいかもしれませんが、影の向きは本来とは 90 度違う方向にできますので、クロッピングが多少ずれる可能性はあると思います。

(2014-11-03 追記)
iX500 を使っている場合、ScanSnap Manager V6.3L22 以降で向きの補正ができるようになったそうです。

(2014-11-03 追記 ここまで)

その他やりたかったこと

RAW 画像の PDF への埋め込み

なるべく高品質なデータを残したいのであれば、RAW データを残すのがいいことになります。ですが元の RAW データは背景部分も無駄に大きく、PDF や JPEG と両方のファイルを残すのももったいないです。

なので理想的には

  • RAW データをやや大きめにロスレスクロッピング
  • 前回「画質がエクセレント PDF 保存する場合の動作」で書いたように、PDF に画像を傾けて埋め込むことで傾き補正
  • カラープロファイルを PDF 側に埋め込む

ができればいいなと。

がんばれば実現できそうな気もするのですが、埋め込む際の原点を計算しなおしたりが手軽にできなそうなので、手を出せませんでした。

残り容量の表示

技術書をスキャンしていると、

処理できる総ファイルサイズの上限(2GB)に達しました。
読み取りが完了した部分のファイルを保存し、最後のページを確認して残りの部分を、再度読み取りしてください。

と言われて、変なページで区切られることがあって。これを防止するために

  • %TEMP%\JpgTmp のサイズをチェック
  • 「この調子でスキャンすると、あと○枚で 2GB に達するよ」みたいな情報を表示

をやりたいなとは思いつつ未実装です。

EasyHook について

フック部分で使っているライブラリです。

こういう処理を書く場合は C++ で書くのが定番だったのですが、C++ だと GUI を作るのがちょっと面倒です。また、普段 GC がある言語を使っていると、C++ でうまくメモリ管理できる自信もなかったりします。

EasyHook を使えば、わりと簡単に .NET からフック処理が呼び出せるので、オススメです。コミットログを見てもらえばわかると思いますが、今回のアプリケーションは EasyHook のサンプルである FileMon を元に作っています。

参考にした URL をいくつか貼っておきます。