OXY NOTES

UWSCでPhotoshopの作業を自動化する方法

画像をフラグにすれば、どんなソフトの処理も自動化できます

UWSCシリーズの第3段。
今回はPhotoshopでの作業を自動化します。

前回のページで解説したEXCELの自動化ではCOMオブジェクトという、ソフトを制御する仕組みが用意されていました。COMオブジェクトを利用すれば、Visual Basicを利用するのと同じように操作することできます。

一方、Photoshopにはそういった仕組みは用意されていません。そのため、処理の実行して終了したことを判断する必要があります。
幸いにもUWSCには指定した画像が表示されたことをフラグにする機能が用意されています。今回はこれを利用して自動化をしていきます。
このページのスクリプトを応用すれば、実質どのようなアプリケーションでも自動化することができます。


UWSCで作業を自動化するための準備

Photoshopにはバッチ処理やドロップレットという自動化のための仕組みが用意されています。
それらで対応可能な処理では面白くないので、「フォルダに入った10枚の画像のうち、画像の横幅が800px以上なら400pxに縮小して上書き保存する」という処理を自動化します。

まず「猫画像」というフォルダをデスクトップに作り、猫の画像を10枚用意してください。(もちろん犬好きなら犬でも結構ですw)

今回は「ぱくたそ」様のかわいい猫画像を利用させていただきました。

UWSCでフォルダの画像をPhotoshopで自動縮小するスクリプト

NEKO_DIR = "C:\Users\ユーザー名\Desktop\猫画像"
NEKO_CNT = GETDIR( NEKO_DIR ) // フォルダ内のファイル名を取得。取得した情報は配列変数のGETDIR_FILES[]に入る

FOR i = 0 TO ( LENGTH( GETDIR_FILES ) - 1 )

	IMG_DIR = NEKO_DIR + GETDIR_FILES[i]
	DOSCMD( IMG_DIR )

	// 新規画像読込みの完了
	WHILE TRUE // 一致するまで実行したいので無限ループ
		chking_result = chking_image( "haikei.bmp" )
		IFB ( chking_result[0] = TRUE ) 
			PRINT "画像読込み完了したよ"
			BREAK // BREAKでWHILEを抜ける
		ENDIF
	WEND

	// Alt+Ctrl+iで画像解像度ウィンドウ呼び出し
	SCKEY( 0, VK_ALT, VK_CTRL, VK_i ) //  仮想キーで指定すべし

	// 画像解像度ウィンドウの呼び出し完了
	WHILE TRUE
		chking_result = chking_image( "kaizoudo.bmp" )
		IFB ( chking_result[0] = TRUE ) 
			PRINT "画像解像度ウィンドウ完了"
			SCKEY( 0, VK_CTRL, VK_c ) // 横幅をコピー
			BREAK // BREAKでWHILEを抜ける
		ENDIF
	WEND

	WINDOW_SIZE = GETSTR( 0 ) // コピーしたデータを代入 0でクリップボードからデータ取得
	PRINT "画像サイズ" + WINDOW_SIZE

	// 画像が800px以上の時は400pxに縮小。それ以外はそのまま閉じる
	IFB ( WINDOW_SIZE >= 800 )
		PRINT "サイズ変更して保存"
		KBD( VK_4 )
		KBD( VK_0 )
		KBD( VK_0 )
		KBD( VK_RETURN )
		SCKEY( 0, VK_CTRL, VK_s ) // 保存
		SLEEP( 0.5 )
		KBD( VK_RETURN )
		SLEEP( 0.5 )
		SCKEY( 0, VK_CTRL, VK_w ) // 画像ウィンドウを閉じる
	ELSE
		PRINT "サイズ変更せずに閉じる"
		KBD( VK_ESC ) // ウィンドウを閉じる
		SCKEY( 0, VK_CTRL, VK_w ) // 画像ウィンドウを閉じる
	ENDIF

NEXT


// 渡された画像があった場合にTrueを返す関数
// img_name		画像のパス
// RESULT		フラグ( TRUE or FALSE )、X軸、Y軸
FUNCTION chking_image( img_name )
	DIM chking_result[2] // 返り値用の入れ物作成(フラグ、X軸、Y軸)
	PRINT "chking_image: " + img_name + "<#CR>"
	ifb CHKIMG( img_name , 1, 0, 0, G_SCREEN_W, G_SCREEN_H, 1, IMG_MSK_BGR4 )
		PRINT "chking_image : TRUE<#CR>"
		chking_result[0] = TRUE
		chking_result[1] = g_img_x
		chking_result[2] = g_img_y
		// 普通に返り値に配列を渡すと「変数: A 次元数が合いません」となるのでsliceを使う
		RESULT = slice(chking_result, 0, length(chking_result)-1)
	else
		PRINT "chking_image : FALSE<#CR>"
		chking_result[0] = FALSE
		chking_result[1] = 0
		chking_result[2] = 0
		RESULT = slice(chking_result, 0, length(chking_result)-1) // 面倒なので上と合わせる
	endif
FEND

1行目の「C:\Users\ユーザー名\Desktop\猫画像」は環境に合わせて変更してください。
あとは画像フラグ用に以下の2つの画像を同じフォルダに保存してください。

スクリプトを実行すると以下のようにPhotoshopが起動し、画像サイズが800px以上の場合は400pxに縮小します。

このように人間による目視や判断が必要な処理も、柔軟に対応することができます。

スクリプトの解説

1~2行目、処理する画像をまとめたフォルダを指定し、GETDIR()でフォルダの中にあるファイルを取得します。

4~52行目FOR-NEXT文で先程取得したファイルの数だけループ処理を実行。

6~7行目GETDIR_FILES[i]で先程取得したフォルダ内のファイル名を取得し、DOSCMD()で実行しています。DOSCMD()コマンドプロンプトを実行する関数です。つまり、コマンドプロンプトにファイルのフルパスを入力してエンターしたのと同じです。(jpegファイルとPhotoshopの関連付けを忘れずに)

10~16行目WHILE-WENDで、条件をTRUEにしています。これは無限ループの条件文です。

ここで重要なのは11行目chking_image()という自作関数です。定義は55~75行目で定義されています。
この関数は画像のパスを渡すと、(TRUE or FALSE、X軸、Y軸)をという配列を返します。指定した画像が表示されるとTrueを返すCHKIMG()という公式の関数を利用しています。CHKIMG()は画像が一致すると座標情報をg_img_xg_img_yに代入するため、それを利用して返り値に利用しています。

今回フラグに利用した画像は以下のような画像です。

これは画像ファイルが読み込まれると表示される「背景」というレイヤー部分の切り取りです。

保存する画像の形式について注意点があり、公式で用意されているCHKIMG()という関数はBMP形式しか対応していません。また、画像の色も厳密に一致しないと認識しません。色幅の許容範囲を指定できる引数もありますが、ほぼ意味がありません。
そのため、BMP画像を保存する形式はファイル形式「Windows標準」、色数「32bit」で保存してください。

キャプチャソフトによっては自動で色数を少なくしたり、アンチエイリアスがかかるものもあるので注意してください。とりあえず私の場合は「WinShot」を利用して問題なく動作しています。

もう1点補足をすると、CHKIMG()関数はかなりのCPUリソースを必要とします。特に、今回の例のように無限ループで連続して実行すると顕著です。そのため、連続して実行する場合はG_SCREEN_W等を使わずに調べる範囲を限定したり、SLEEP()関数で適度なディレイ(0.1秒など)を入れることをおすすめします。

自作のchking_image()関数ですが、今回の解説とは別の機会に作成したものです。そのため、今回は利用しない座標情報も返り値に含まれますが、指定した画像が表示された際にTRUEを返すという機能のために再利用しています。
このように普段の業務に使う関数は限られています。一度作ってしまえば応用が効くので、よくあるパターンは関数にしておくと後で楽ができます。

12~15行目IFB-ENDIFchking_image()の返り値がTRUEになった場合にBREAKで10行目のWHILEを抜けています。つまり「一致する画像が画面に表示されるまで無限ループする」という処理です。

ちなみにPRINT “画像読込み完了したよ”はログ表示用です。このように要所要所で結果を出力しておくとエラーを把握しやすくなります。

10~16行目をおさらいをすると「指定の画像が表示さるまで無限ループする」という処理をしています。

なぜこのような処理が必要なのでしょうか?
前のページで解説したEXCELの場合はCOMオブジェクトを利用していたため、簡単に挙動を制御できましたが、多くのソフトではそのような仕組みは用意されていません。そのため一つ一つの処理が終了してから次の処理を実行する必要があります。今回の例で言えば、7行目DOSCMD( IMG_DIR )によって、Photoshopで画像を読み込み、次の処理が可能な状態になったかを判断する必要があります。

簡単な処理であればSLEEP()関数を利用して、多めにディレイタイムを設定しておけば問題ありません。
しかし「0.1秒でおわることもあれば、10秒かかることもある」といった処理の場合、保険として10秒の方に合わせる必要があります。(今回の画像読込みの例で言えば、100MBのRAWファイルと、100KBのjpegファイルでは読込み時間は全く異なります)

長い方の時間に合わせれば、早い処理の場合に無駄な待ち時間が多くなります。そんなときに読込みが完了した時に変化する画像をフラグにすれば、処理が終了してからのタイムラグが少なくて済みます。

19行目SCKEY()で複数キーの同時押しをシミュレートしています。仮想キーについては「仮想キー一覧 | UWSC コバヤシ式」をご覧ください。

21~29行目、ここでも上と同じように、画像解像度ウィンドウが呼び出されたことを確認してから次の処理を行うために、ウィンドウ画像の一部をフラグに利用しています。
今回はおさらいとして画像をフラグに利用しましたが、ウィンドウを呼び出すといった処理速度にばらつきが無いものの場合はSPEEP()関数で時間を入力したほうが生産的です。

ちなみに画像解像度ウィンドウは呼び出した時点で、横幅の項目を選択した状態のため、SCKEY( 0, VK_CTRL, VK_c )で値をコピーしています。

31行目、クリップボードにコピーした値をWINDOW_SIZE = GETSTR( 0 )で取得。

35~52行目IFB-ENDIF画像の横幅が800px以上の時は400pxに縮小800px以下の場合はそのまま閉じるという処理をしています。
こちらは処理の合間にSLEEP()関数を利用して簡単に済ませています。


UWSCとPhotoshopを連携して画像サイズを変更する、という処理の自動化について解説しました。
今回のように画像や入力データをフラグにすれば、どのようなソフトでも応用することが可能です。

このページの情報が「毎日同じような処理を繰り返している」という方のお役に立てば幸いです。

ちなみにゲームでこの方法を利用するのはやめましょう。多くの場合規約違反になります。また、ほとんどのゲームでUWSCによる自動化は検知されます。(マウスの移動や、クリックする場所、時間等を全てランダムにしても検知は可能です)