ようこそゲストさん

色々日記(ざ・めも)

メッセージ欄

2013年12月の日記

一覧で表示する

2013/12/29(日) WindowsでUSBデバイスが最後に挿された日付を確認する

2013/12/29 16:53 PC(全般)
あるUSBデバイスが最後にPCに認識された日付を確認する方法。
for Windows7。

以下を参考。
NetAgent Official Blog : USBメモリとレジストリ

手順をまとめると、
  1. そのデバイスのベンダ名、デバイス名を把握する
  2. HKEY_LOCAL_MACHINE\SYSTEM\MountedDevicesからベンダ名、デバイス名で該当デバイスのGUIDを探す(バイナリデータ内にベンダ名、デバイス名が入っているので頑張って探す)。
  3. HKEY_USERS\<ユーザSID>\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2から前項で調べたGUIDを持つキーを探す。
  4. 前項で得たキーのタイムスタンプを調べる。
タイムスタンプの確認にはタイムスタンプを見られるタイプのレジストリエディタを使う。もしくは、Windows標準のレジストリエディターを使用しtxt形式でエクスポートして確認する。

以下を参照。
レジストリ・キーの最終更新日時を調べる− @IT

2013/12/28(土) IE8のtable表示バグメモ

2013/12/28 26:41 PC(プログラミング)
かなり以前に書いたメモから起こしてるので、ちょっとおぼろげ。

IE8において、特定の条件下でtableタグのレンダリングに以下の問題が発生する。
問題の内容は、
・表の外枠の上罫線が欠ける
・表の外枠の左罫線が欠ける

先にコードを提示する。
IE8で以下のようなコードをレンダリングすると発生する。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
	<title>test</title>
	<style type="text/css">
		table{
			border-collapse: collapse;
		}
		td,th{
			border: solid 1px black;
		}
		div{
			overflow: hidden;
		}
	</style>
</head>
<body>
	<div>
		<table>
			<thead>
			</thead>
			<tbody>
				<tr>
					<td>a</td>
					<td>b</td>
					<td>c</td>
				</tr>
			</tbody>
		</table>
	</div>
</body>
</html>
条件は以下の通り。

・ブラウザ: IE8
・モード: 標準モード
・tableの親divで"overflow: visible"以外を指定
・border: collapse
・空のtheadタグがある

必要十分かどうかは不明。

主たる原因は、空のtheadタグがあるから。
これを消すと罫線が表示される。

バグという表現を使ったが空theadは元々validate通らないので、IE8が必ずしも悪いわけではない。ただし他のブラウザで線が欠けるものは発見できなかった。

空theadを使うなと言えばその通りだが、IE対応かつ表の固定ヘッダ(Excelのような)を作ろうとするとsampleなどにもちょいちょい出て来るコードなので多少留意をしておくこと。

2013/12/13(金) fi-6130のTWAINがフォーカスを取るのを抑止する

2013/12/13 16:27 PC(全般)
fi-6130等、Fujitsuのfi系ドキュメントスキャナのTWAINドライバウィンドウが1枚スキャンするごとにフォーカスを持っていってしまう問題。スキャン中他の作業、特に入力作業が出来ない。

とりあえずAPIフックで対処可能。

Windows API Hooking Tutorial

上を参考に、SetForegroundWindowを握りつぶせば良い。

最初単にグローバルフック(SetWindowsHookEx)でどうにかなるような気がしていたのだが、WM_ACTIVEAPPメッセージを握りつぶそうとしてもうまくいかなかった(WM_ACTIVEAPPが飛んできたタイミングは捕まえられる。そこで元のウィンドウにフォーカス移すのはちょと……)。

実のところWindowsのメッセージ機構の理解にあやしいところがあって、キーボード・マウス以外のメッセージにキャンセル機構がないのか、SetWindowsHookEx自体の制限か、それともWM_ACTIVEAPPメッセージは通知だけで、ウィンドウのアクティブ処理自体はエクスプローラ側の触れない領域にあるのかといったあたり判断できてない。C++でWin32ネイティブアプリ書いて、WndProc内であれこれやってみれば結論が出るんだろうけど、今回は時間がないので次回以降の課題。

.NET系でもマウス・キーボードのグローバルフックがかけられることは覚えておこう。

ソース整理できたらそのうち載せたいけども、元コードのライセンスがわからないな……

2013/12/13(金) 自炊を突き詰めてみた

2013/12/13 15:23 PC(全般)
自炊、いわゆる書籍の自家電子化。

自分が妥協できるやり方で、どれだけ高速化・効率化できるかを突き詰めてみた。

所要時間

突き詰めた結果、こんな感じ。

おおざっぱに、前処理 -> スキャン -> 後処理となり、

前処理: 人力
スキャン: 自動
後処理(操作・目視判定): 人力
後処理(自動): 自動

となる。

ページ数依存の時間

200ページ(背厚おおよそ10mm程度)ごとに、5分(スキャン:4分, 後処理(自動):1分)

冊数依存の時間

1冊ごとに、3〜4分(前処理(裁断・タイトル作成):2分, 後処理(操作・目視判定):1分)

その他ミスによって生じるロス時間

ミス1回ごとに、だいたい10分。
(ミスのほとんどは、スキャン時に発生。紙サイズ自動判定のミス、ノリ残りによる給紙ミス、紙質混在による給紙ミスがほとんど)

モデルケース

[a]週刊少年誌2冊 = 50mm = 1000ページ => 5分 * 5 + 3分 * 2 = 31分
[b]薄い本15冊 = 50mm = 1000ページ => 5分 * 5 + 3分 * 15 = 70分

こんな感じ。正直集中力が続かないので(特に冊数が多い場合)、実作業時間はこれに1.2〜1.5掛けになるが最大効率だとこの数字になる。

複数の本を対象にまとめて作業すれば、パイプライン化によって前処理とスキャンを同一時間に行うことは可能(ただし、本当にかかりっきりになる)。

方法

自分のやり方をざっと書いておく。

機器構成的には以下のような感じ。
・中国製裁断機(XD-3203A)
・Fujitsu fi-6130
・PC(Core-i5 2500K, 16GB, HDD)

前処理

自炊する対象を決める
最終的にはこれが一番重要。とっとくか、捨てるか、自炊するか即断。
裁断
使用している裁断機(XD-3203A)は精度が低いのでちょっとした工夫・コツがいる。

突き当ての遊びが大きく垂直が出てないので、突き当てをちょっと刃側に寄せて位置合わせをする。

裁断面が斜めにならないように(特に厚い本で斜め切りになりやすい)、紙押さえ下部と紙押さえの接地部にゴムシートなどの滑り止めを貼っておく(参考: 漫画をスキャナで電子書籍化する初心者向け自炊解説サイト 裁断機で斜めに切断・切れないようにする解決方法)。紙押さえを強く押し下げたあと、ちょっと緩めて押し下げるを何度か繰り返す。さらに裁断時にも左手で紙押さえを押し下げながら裁断する。

ここまでやってもほどほどの精度なので、裁断機は良いもの(自炊裁断機200DXなど)を使った方がよい。
チェック
裁断した束を、スキャナまで移動する間に、以下のことをチェックする。
[1]特殊サイズ・特殊紙がないか
[2]くっついているページがないか(特にカラーページ・表紙の周り)
[3]ノリが大きく残っていないか

[1]に該当する場合、スキャナに通るかどうか考える。通らないのであれば追加で裁断をするか、フラットベッドで取り込むか、スキャンを諦めるか決める。

[2][3]に該当する場合、剥がして手当てする。
タイトル作成
本タイトルor誌名、お好みで著者・サークル名・出版社・出版年・ジャンルなどをテキストエディタで作成する。

出版された書籍のみを扱うのであれば、バーコード読み込みからタイトルを自動生成するスクリプトなどを生めば効率が上がるかも知れない。

ただし、amazon DBはかなりの表記揺れがあるため、シリーズでタイトル揃えるといった要望を満たせないかも。古い本ではバーコードがなかったり、JANコードがDBになかったりということもある。amazonを万能とは考えないこと。

私は秀丸で、項目(ジャンル, 著者, タイトル)をタブ区切りにしたファイルを作り、マクロでクリップボードへコピーまでやっている。
//一般的な書籍タイトル名を生成するマクロ
movetolineno 1, 3;
deleteline;
movetolineno 1, 2;
beginlinesel;
copy;
paste;
//著者名有り
replacedown "([^\\t]+)\\t([^\\t]+)\\t([^\\t]+)\\t([^\\t]+)", "(\\1) [\\2 (\\3)] \\4", regular;if(result == 0){
	//著者名無し
	replacedown "([^\\t]+)\\t([^\\t]+)\\t\\t([^\\t]+)", "(\\1) [\\2] \\3", regular;}
if(result == 0){
	//団体名・著者名無し
	replacedown "([^\\t]+)\\t\\t\\t([^\\t]+)", "(\\1) \\2", regular;}
movetolineno 1, 3;
beginlinesel;
copy;
これを、以前のBTScanTool(AutoIt!でBTScanをちょっと改良 - 色々日記(ざ・めも))にCtrl+A, Ctrl+Vして、フォルダ名をBTScanにセットする。

BTScanの入力開始ボタンを押下して、フォルダを作成。

スキャン

fi-6130の給紙枚数はだいたい10mmくらいまでなのでそれくらいごとにスキャナに通す。
このとき、摩擦が少ない紙(カラーページなど)はセット時の束中で一番最後に取り込むように区切るとミスが少ない。fi-6130の給紙能力は素晴らしく優秀だが、紙質混在原稿ではミスをすることがあり、摩擦が大きいページを先に吸ってしまうことがある。

原稿をさばいて、先に給紙するものほど奥に入るように若干斜めにセットする方がミスが少ないのはプリンタと同じ。

スキャナが止まってから束に割ると効率が落ちるため、作業スペースを確保して先に全部束に割ってしまう方がいい。少なくとも次にセットする束は準備しておくと効率がよい。

スキャンは、BTScan + fi-6130(TWAIN)で行う。

基本的に全て両面、300dpi, カラー, bmp, 自動用紙サイズ検出、4桁1始まり連番でスキャン。

特殊紙は都度単体でスキャン。

自動用紙サイズ検出に失敗したケースでは、黒背景でB5,A4等の規定サイズでスキャン。

コミック等表紙については、長尺で取り込めるものについては横向き長尺でスキャン。

現状、BTScan以上に優秀なソフトがないのだが、BTScanはプロファイルを自動更新してしまうなど使い勝手が悪い。スキャンパートは実時間依存大であり、手戻りが多大なロスになるため極力どんな本でも同じ設定で出来るようにすること。BTScanのプロファイルは信用しないこと。

なお、fi-6130含むfi系のTWAINドライバは1枚スキャンするごとにフォーカスを持って行く。これだとスキャン中は他の作業が出来ないため結構きつい。APIフックで何とかする方法はあるのでfi-6130のTWAINがフォーカスを取るのを抑止する - 色々日記(ざ・めも)を参照。

後処理

自作スクリプトとZoner Photo Studio 15, RalphaPlus, SpringM等を駆使する。
サイズ取得
スキャンしたフォルダで自作Rubyスクリプトを実行し、最小サイズと全体のずれを取得する。
$KCODE = "Shift-JIS"

require "rubygems"
require "image_size"
require 'win32/clipboard'

max_width = 0
min_width = 99999
max_height = 0
min_height = 99999

Dir.glob("*.bmp"){ |f|
	open(f, "rb"){ |fp|
		img = ImageSize.new(fp.read)
		
		if max_width < img.width then
			max_width = img.width
		end
		
		if max_height < img.height then
			max_height = img.height
		end
		
		if min_width > img.width then
			min_width = img.width
		end
		
		if min_height > img.height then
			min_height = img.height
		end
		
	}
}

width_diff = ((max_width.to_f-min_width)/max_width*10000).round.to_f/100
height_diff = ((max_height.to_f-min_height)/max_height*10000).round.to_f/100

param = "W/2-#min_width/2,H/2-#min_height/2,#min_width,#min_height\n"

output = ""
output += "w:#min_width-#max_width #width_diff%ずれ\n"
output += "h:#min_height-#max_height #height_diff%ずれ\n"
output += "\n"
output += param

open("c:\\**documents**\\ralpha_trimming_param\\ralpha_trimming_param.txt", "w"){ |wp|
	wp.write output
}

Win32::Clipboard.set_data(param)

IO.popen "c:\\**program**\\hidemaru\\hidemaru.exe c:\\**document**\\ralpha_trimming_param\\ralpha_trimming_param.txt"
適当に書いたのでメチャクチャ。実行すると、秀丸が立ち上がってこんなのが出る。
w:1642-1658 0.97%ずれ
h:2041-2045 0.2%ずれ

W/2-821,H/2-1020,1642,2041
プロンプトでやると閉じ忘れたときに一手間増えるので敢えて秀丸に出力する(スキャンフォルダを削除するときに「使用しているアプリケーションがあるため〜」となる)。

最後の1行はRalphaPlusに投げるためのパラメータ。自動的にクリップボードにコピーされている。

ずれが2%を超えているケースは、スキャン時に何かが起こっている可能性が高いので見直しをかける。
目視チェック
サイズ取得と並行して、Zoner Photo Studio 15を立ち上げる。Zoner Photo Studioは起動ディレクトリを指定できないので、AutoIt!で起動ディレクトリを渡してやる。
$Title = "Zoner Photo Studio 15 FREE"

Run("C:\\**program**\\Zoner\\Photo Studio 15\\Program64\\Zps.exe")
WinWaitActive($Title)

WinActivate ( $Title )

ControlClick ( $Title, "", 100 )

ClipPut($CmdLine[1])Send("^VENTER")
このAutoIt!のスクリプトにディレクトリ名を引数として渡してやると、Zonerを立ち上げたあとにそのディレクトリに移動してくれる。

ここで、カラーページを選択しRalphaPlusにD&D。Zoner上にいったん戻り、次の作業のためにCtrl+Iして選択を反転。
bmp->jpg(カラー)
ここから先はRalphaPlusでの処理。

プロファイルをカラーに切り替え、トリミングのパラメータに"X座標、Y座標、幅、高さ(px)"指定でクリップボードのデータをCtrl+Vする。

カラープロファイルでやっているのは
・レベル補正
・トリミング
・リサイズ
・アンシャープマスク
・ノイズ除去

F5で実行。Ctrl+Delでクリア。
bmp->jpg(モノクロ)
再度、Zonerに戻って現在選択されているファイルをもう一度RalphaPlusにD&D。

プロファイルをモノクロに切り替え、トリミングのパラメータに"X座標、Y座標、幅、高さ(px)"指定でクリップボードのデータをCtrl+Vする。

モノクロプロファイルでやっているのは
・グレースケール化
・レベル補正
・トリミング
・リサイズ
・アンシャープマスク
・ノイズ除去

適当なページを選んで、レベル補正のみ確認する。
裏移りが極端に酷い場合、若干白飛ばしを強めにする。
薄いグレースケール・トーン飛びが酷い場合、若干白飛ばしを弱めにする。

F5で実行。
bmp移動
現時点で、スキャンフォルダにbmpとjpgが混在しているため整理する。
スキャンフォルダで、backフォルダを作成しbmpファイルをそこに移動するスクリプトを実行。
$BACKUP_DIRNAME = "back"

if not File.exist?($BACKUP_DIRNAME) then
	Dir.mkdir($BACKUP_DIRNAME)
end

Dir.glob("*.bmp"){ |file|
	File.rename(file, "back/" + file)
}
チェック
Mangameeya等のビューアでざっと後処理したjpgをチェックする。
削除
チェックして問題無ければ、bmpの入ったbackフォルダを削除。
圧縮
Zoner等がまだひらいていれば閉じる
WinRARにスキャンフォルダをD&Dして無圧縮・リカバリレコード付きで圧縮する。

これにて完了。

今後の高速化

スキャンデータストレージとしてHDDをRAMディスク or SSDに変更

 スキャン周り・後処理について高速化が期待できる。
 RAMディスクの場合、今のやり方ではまとめて作業すると簡単に使い切ってしまうのと後続作業を後日に回したいときがネックか。
 SSDは効用次第だが、このためだけに導入するのは疑問。

BTScanの上位互換ツールの発見 or 開発

 BTScanがもうちょっと使い勝手が良ければ、スキャン時に特殊紙・カラーを選り分ける、jpegでスキャンするなどをした方が効率が上がる可能性がある。現状のBTScanでこれをやると、プロファイル仕様の問題でどうしてもミスが増える。

可読性を多少犠牲にする

 モノクロとカラーで後処理を分けているが、これを一本化すればかなり人力判定・操作コストが減る。ただし、モノクロページはやはりグレスケ化した方が綺麗ではあるのでどこまで割り切るか。

機器の更新

 CPUについては、高速化すれば当然後処理が多少早くなる。とはいえ抜本的な改善はintel CPUでは2015年のSkylake待ちである。AMD GPGPUが進めば面白いが…?
 ドキュメントスキャナについては、fi-6130でも既に準業務機という位置づけなのでこれより早いスキャナはなかなか手に入るような価格では出てこないとは思うが、なにがしか技術革新があるかも知れない。
 裁断機については、ダーレ200DX等に変えることで(裁断可能厚そのものは減少するが)、垂直性や斜め切りが改善できるならば結果的に効率化できる可能性がある。

総括

自炊は時間と空間のトレードである。

使われる時間はなんら生産的でも文化的でもないため、とにかく辛い。人には絶対勧めない。入手性が高い本であれば手放してまた読みたいときに買い直すも良し、電子版があるならそれを買うも良し。

トレード対象になる時間を鑑みて、本当にその価値があるか考えるようにしたい。特にコミックには手を出さない方が無難。20分で読める本の自炊に最速8分かかるということを肝に銘じる必要がある。解像度が低かろうが、カバー裏が収録されて無かろうが、Kindleがあればもうそれでいいじゃない。amazon万歳。

赤松先生が以前提唱していた、電子化されてない本をアップしたら、版権取りと電子書籍販売まで代行してくれるサービスがあったらいいのに……