独自形式の電子書籍が嫌い
CRC Pressで電子書籍の教科書を買ったら、まんまと独自形式だった。VitalSource Bookshelfとかいう専用アプリで読まなければならず、色々と不便。印刷が許されているので、そこからPDFにする事もできるのだけど、1回あたりの印刷で2ページしか印刷できない、とかいう制約付き。じゃぁ、スクリプトで自動化するか、と。
AppleScriptで挫折
この手のGUIの自動化をしようと思ったらAppleScriptが便利っていう認識だったんだけど。印刷ダイアログから"Save as PDF"を選ぶのがうまくいかずに挫折。せっかくだからWindowsでPowerShellでも試してみるかな、という気分に。でも、あんまり真面目に勉強する気もない。
Windows PowerShell ISE
AppeScript Editor的なやつ。ArduinoとかのIDEと似た感じで、適当にコード書いて再生ボタンを押せば実行できる。とりあえず最低限度の知識で必要最低限のスクリプトを組むのが目標。Windowsの場合、キーボードだけで大抵の操作には手が届くので
- 変数を使ってループを回す
- 変数からファイル名を生成する
- キーボード操作をエミュレートする
- タイミングをとる
ってくらいができれば問題なさそう。
基本処理の把握
変数を使ってループを回す
for ($i = 1; $i -lt 250; $i += 2) {
}
なんかしらの言語知ってれば読めるような基本的なforループ。-lt
が無駄に「俺Shellなんだぜ」感。これで1ページから2ページずつで250ページまでってループが回せる。
変数からファイル名を生成する
あとでまとめて1ファイルにする時に便利なようにソートしやすいファイル名をつけたい。
$file = "file-" + $i.ToString("000") + ".pdf"
これでfile-001.pdf
みたいな名前が作れる。000
はprintfで言うところの%03d
。
キーボード操作をエミュレートする
OS標準のGUIコンポーネント使ってれば、大抵はTABで選んでEnterで決定、Alt-*系のバインドでメニューにアクセスしてカーソルで選択……って感じでキーボードだけで用が足りる。この辺りは昔からWindowsのよく出来てるところ。
[System.Windows.Forms.SendKeys]:: SendWait("{TAB}")
これでアクティブなウィンドウに対してTABキーのイベントが発生する。この手の特殊キーは{}
で囲めば指定でき、{ENTER}
とか{DOWN}
など予想されるような文字列を入れればたいてい当たってる。
あと、Ctrlキーを押しながらは^
を前につける。例えば印刷したければCtrl-Pなので"^p"
を指定すれば良い。
タイミングをとる
Start-Sleep -s 10
10秒間待つだけの簡単な処理。-s
の引数で待ち時間を指定できる。
印刷の自動化の実際
それ以外の複雑な指定、例えばプリンタの指定(Microsoft Print to PDFを選ぶ)や印刷の詳細設定は、ひとまず最初の1回を人力で行う事で指定する。使うプリンタや、Microsoft Print to PDFが出力する先のフォルダなどは一度選べばデフォルトになるので、スクリプトで指定する必要もなくなる。
# ここで3秒待つ間に手動でBookshelfをアクティブウィンドウにする
Start-Sleep -s 3
for ($i = 1; $i -lt 250; $i += 2) {
# 印刷ダイアログを開く
[System.Windows.Forms.SendKeys]::SendWait("^p")
Start-Sleep -s 2
# 開始ページ指定までTABで移動
[System.Windows.Forms.SendKeys]::SendWait("{TAB}")
[System.Windows.Forms.SendKeys]::SendWait("{TAB}")
# テキスト全選択した上で開始ページ$iで上書き
[System.Windows.Forms.SendKeys]::SendWait("^a")
[System.Windows.Forms.SendKeys]::SendWait("$i")
# 終了ページやページ数は飛ばしても平気(事前に最終ページを指定しておければ、
# 例えば1-100ページみたいな指定になっていても頭の2ページだけ印刷される)
[System.Windows.Forms.SendKeys]::SendWait("{TAB}")
[System.Windows.Forms.SendKeys]::SendWait("{TAB}")
[System.Windows.Forms.SendKeys]::SendWait("{TAB}")
# 印刷OK
[System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
Start-Sleep -s 2
# プリンタ選択(Microsoft Print to PDF)
[System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
Start-Sleep -s 2
# 出力するPDFファイル名を指定
$file = "file-" + $i.ToString("0000") + ".pdf"
[System.Windows.Forms.SendKeys]::SendWait("$file")
[System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
Start-Sleep -s 10
}
全くもって雑なスクリプトですが。これをISEに書いて再生、問題の電子書籍を開いてるBookshelfを3秒以内にアクティブにしてあげれば、あとはひたすら変換してくれる。GUIのレイアウトやらはOSのバージョンやインストールされてるドライバの差異なんかでも変わると思うので、キーボード叩く回数なんかは適当に環境に合わせて調整する必要があるかも。遅いマシンでは待ち時間も長めに。
ちなみに変換したPDFには毎ページ購入者のメールアドレスと著作権の警告文が入るので、悪いことには使えませんよ。