>   >  COYOTE流テクニカルTIPS:TIPS 05:【Photoshop】スクリプトで処理の内容を作ろう
TIPS 05:【Photoshop】スクリプトで処理の内容を作ろう

TIPS 05:【Photoshop】スクリプトで処理の内容を作ろう

クリーク・アンド・リバー社の社内CGスタジオであり、ゲームの3DCGグラフィックス制作を中心に手がけているCOYOTE 3DCG STUDIO。本連載では、同社のTAチームによる制作に役立つ技術TIPSを紹介していく。

TEXT_中林伸和 / Nobukazu Nakabayashi(COYOTE 3DCG STUDIO)
EDIT_小村仁美 / Hitomi Komura(CGWORLD)

はじめに

戦国三英傑の豊臣秀吉の好きなところは天下人に似合わない気さくなイメージ。TAは人と話すことも重要なのでうらやましいスキルです。こんにちは、COYOTE 3DCG STUDIO テクニカルアーティスト(以下、TA)戦国大好き人間の中林です。

前回から、当社ブログにも掲載したPhotoshop内製ツール紹介『CRPS_指定ファイル保存』の制作を例として、Photoshopのツール制作に関するTipsを3回に分けてお届けしています。今回はその第2回です。

1:オープンソースエディタBracketsを使ってHTMLでUI作成(第4回
2:スクリプトで処理の内容を作ろう(今回)
3:認証の自動化の紹介

制作事例として紹介するツール「CRPS_指定ファイル保存」は、「複製→レイヤーを統合→画像解像度の変更→フォルダ選択→保存→複製削除」を1クリックで行うというシンプルなものです 。

  • ◀「CRPS_指定ファイル保存」UI

前回は外側のUIをつくる方法を紹介しましたが、今回は中身の処理について説明していきたいと思います。

基本的な処理はJavaScriptとJSXに分かれる

中身の処理に関しては、主にUIを操作するJavaScriptと実際にPhotoshop内を操作するJSXに分かれます。JavaScriptは聞き馴染みのあるスクリプト言語ですが、一方JSXは「(古い)JavaScript+Adobe独自のコマンド」を組み合わせたスクリプトです。

ちなみにJSXに関しては困ったことに、ネット検索すると主に以下の3つが出てきます。

1:Reactで用いられるJavaScriptの拡張構文
2:Adobe製品に搭載されているJavaScriptマクロ
3:DeNAで開発されたWebアプリケーション向けのプログラミング言語

......みんなJavaScriptの進化系にXを付けるのが好きなんだなぁ。おかげで検索する方は大変です。知りたい情報は、2番目の「Adobe製」のものなので、ネット検索する場合は「JSX -React -altJS」などと、マイナス表記で1番目や3番目の情報を省くことをオススメします。この記事では後にも先にもJSXはAdobeのスクリプトのことを指します。

ところで、JSXでスクリプトを始めて、さらにネット検索すると「ScriptListener」を使おう、という情報が多く出てきますが、個人的にはあまりオススメできません。これを使うとMayaでいうスクリプトエディタのMELのようなコマンドの情報を期待しますが、出てくるコマンドはアクション用にガチガチに変換された情報で、参考にならないのです。ちゃんとJSXのコマンドを調べ、自分で組み合わせて作成するのが一番です。

JSXのコマンドのリファレンスについては、こちらの日本語サイトがオススメです。独自で調べたコマンドを日本語で解説してくれています。

●中綴製作所
http://nakatoji.lolipop.jp/index.php/extendscript
●Photoshop JavaScript Reference
http://www.openspc2.org/reibun/Photoshop/ref/

また、英語ではありますがJSXの公式のコマンドリファレンスもあります。多少、翻訳の手間はありますが多くのコマンドを知ることができます。

●Adobe Photoshop Scripting
https://www.adobe.com/devnet/photoshop/scripting.html

Step 01:JavaScriptでUIの操作

ちなみにJavaScriptは複数の書き方がありますが、今回は、前回紹介したBracketsエディタの例を参考につくりました。JavaScriptのメインのファイルはBracketsのjs/main.jsになります。

【Hello World】を参考にすると、「function init()」内に以下の命令があります。

●index.html

html
	<button id="btn_test" class="topcoat-button--large hostFontSize">Hello World</button>

●main.js

javascript
	$("#btn_test").click(function () {
		csInterface.evalScript('sayHello()');
	});

これは、htmlと同じ名前のボタンをクリックしたときに処理をするというながれになっています。今回作成する「CRPS_指定ファイル保存」では主に以下の3つの作業を行なっています。

1:UIの変更情報の保存
2:起動時のUIへの情報反映
3:JSXに変数を渡して実行

1-1:UIの変更情報の保存

例えばpngで保存する場合、画像1枚保存して終わりではなく、ある程度の回数はpngで作業をすると思います。しかし、ツールが起ち上がるたびに初期化されると再設定するのにストレスが溜まります。

そこで、画像形式を変更したタイミングで、localStorageにその情報を保存するようにします。localStorageとは、JavaScriptでデータをブラウザに保存するしくみです。

下記はチェックボックスを変更したときに保存を行う例です。

●index.html

html
	<input type="checkbox" id="COYOTE_chkPng_CBox" class="checkbox-input">
 <span class="checkbox-parts" label="png" ></span>

●main.js

javascript
	$("input#COYOTE_chkPng_CBox").change(function() {
		var tmp = document.getElementById("COYOTE_chkPng_CBox").checked;
		localStorage.setItem("COYOTE_chkPng_check", tmp);
	});

これは一例ですが、button以外の全てのメニューが保存対象で、変更するたびに各localStorageに情報を保存しています。

1-2:起動時のUIへの情報反映

基本的には1-1で保存した情報をツール起動時に反映するだけです。若干面倒なのは、localStorageは文字列に変換されてしまうので、そのままでは渡せないケースがあることです。その場合は、文字列をif文で比較し、内容に沿って情報を渡すようにします。

●index.html

html
	<input type="checkbox" id="COYOTE_chkPng_CBox" class="checkbox-input">
 <span class="checkbox-parts" label="png" ></span>

●main.js

javascript
 var tmp = localStorage.getItem("COYOTE_chkPng_check");
 if(tmp == "true"){
  document.getElementById("COYOTE_chkPng_CBox").checked = true;
	});

ツールの設定は、ツール側が記憶できるようにしないと地味にユーザーが面倒です。作る方も面倒だという意見もありますが、作る方の手間は1度だけです。しかし、ユーザーの手間は使い続けるたびに何度も発生します。筆者は1度の手間と複数回の手間を天秤にかけて、ツールをつくるときは絶対にUI情報を記憶させるようにしています。

1-3:JSXに変数を渡して実行

ボタンをクリックしたときに、JavaScriptの処理からcsInterface.evalScript(JSXの関数)でJSXの関数を実行します。ただし、JSXから直接HTMLの情報を取得することはできないので、JavaScriptの時点で必要な変数情報を集めておきます。

●index.html

html
	<button id="COYOTE_duplicate_btn" class="topcoat-button--large hostFontSize">選択画像の複製保存</button>

●main.js

javascript
$("#COYOTE_duplicate_btn").click(function () {
	//
	// 保存するイメージの形式をチェックボックスから取得(一部省いてます)
	var imageList = [];
	if(document.getElementById("COYOTE_chkTga_CBox").checked){
		imageList.push('tga');
	}
	if(document.getElementById("COYOTE_chkPng_CBox").checked){
		imageList.push('png');
	}// テクスチャの変更したいサイズ
	var sizeX = document.getElementById("COYOTE_sizeX_id").value;
	var sizeY = document.getElementById("COYOTE_sizeY_id").value;
	// JSXに変数を渡して実行
	csInterface.evalScript('COYOTE_saveDuplicateimage("' + imageList + '","' + sizeX + '","' + sizeY + '")');
});

ここではlist形式で変数を渡していますが、JSX上ではカンマ区切りの数列も文字列になってしまいます。なので、改めてJSX側で分割する必要があります。

●〜.jsx

javascript
function COYOTE_saveDuplicateimage(imageList, sizeX, sizeY){
	imageList = imageList.split(","); // 文字列を","で区切ってリスト化
	// 以下処理が続く......
}

1-3':JSXの変数を戻す

JSXからJavaScriptに変数を戻したい場合もあると思います。その場合の例として、JSXから画像の横幅を取得してJavaScriptで利用するケースを紹介します。

●〜.jsx

javascript
function getDocumentSizeX(){
	return parseFloat(activeDocument.width);
}

●index.html

html
	<input type="text" id="COYOTE_sizaX_id" value="2048" onKeyup="this.value=this.value.replace(/[^0-9]+/i,'')" size="3" maxlength="4">

●main.js

javascript
csInterface.evalScript('getDocumentSizeX()',function(cb){
	// メニューの
	document.getElementById("COYOTE_sizaX_id").value = cb;
});

これはfunctionで戻り値を変数で受け取って利用しています。さすがに画像サイズの取得はJSXでないとできないので、戻り値を利用します。

次ページ:
Step 02:JSXでの処理の紹介