スクリプトの刑に処す

作業が活気付いてくると、日々の雑事はたとえ些細なレベルでも面倒で厄介です。ちょいちょい作業の腰を折るので。

 

現在、新しいタイプの作画技術ではタイムシートをクラウドの表計算で記しています。一方、原画上がりに相当する作画上がりはPSDファイルのレイヤー構造で、規則(階層や名称など)を定めてファイルを出力しています。

 

つまり、PSDファイルのレイヤー構造は、セル重ねの構造であり、彩色作業枚数でもあります。

 

新しい技術ではもはや「ABCDE」というセルの名称は廃止し、実際のキャラの略語で表し、各パーツと内容を、レイヤー名で記しています。

 

例えばタローの顔と髪の毛の線画なら、

 

taroというレイヤーセットの

face.line

hair.line

 

‥‥といった具合です。

 

これらは、アクションシート上では、

 

taro as contents

face as Obj ID

hair as Obj ID

 

‥‥のように表記されます。‥‥‥というか、そのように記述しなければ、次の工程の作業者が理解できません。ちゃんと階層構造も名前も正確に記さなければ、「これは誰の髪の毛?」ということになります。

 

‥‥まあ、絵の内容を見れば、彩色作業者さんは良きに計らってくれるのですが、だからといってレイヤー名やレイヤー構造や伝票の表記を滅茶苦茶なまま渡してしまうのは、甘え過ぎを通り越して未来の作業体制の不安にもなりましょう。

 

ちゃんと規定して整然と取り回すフローを確立するのは、コンピュータを導入した後だからこそ、改めて、重要な取り組みとなります。

 

 

とはいえ。

 

こうした事務的な「レイヤー名 to 表計算の記述」を手作業でやると、地味に面倒。

 

大した所要時間ではないですが、文字を打ち間違えないように神経を使いますし、もしかしたら、レイヤー名を書き写し忘れる人災も起こりましょう。

 

そんな雑事は、

 

スクリプトの刑に処す

 

‥‥です。コンピュータの一番得意な、1文字も間違えずにコピペする能力を使わない手はないです。

 

Photoshopのレイヤー名を順々に取得して、promptのテキスト欄に書き出せば、後はコピーして、表計算に「内容だけペースト」すれば、一番面倒な「レイヤー名を書き写す」作業を自動化できます。

 

まあ、一番良いのは、そもそもアクションシートと連動してAfter EffectsやPhotoshopが動作することなのですが、今はそんなに欲張らずに、地道に面倒な手間を軽減することで確実にミスと時間消費を抑えます。

 

 

エレガントな統合作業環境を目指すのは、見果てぬ夢として抱き続けて、今は、とにかく人の時間を奪う雑事を、「思いついたらスクリプト」でプチ自動化して、どんどん新しい取り組みによる映像制作を進めましょう。

 

単に第1階層のレイヤー名だけを取得するなら、

 

var adys=app.activeDocument.layers;
var text="";
for (var i=0;i<adys.length;i++){
    text=text+adys[i].name+"¥r";
}
prompt("レイヤー名の一覧です",text);

 

‥‥と、改行(バックスラッシュとアール)で区切ったテキストを生成できます。

 

まあ、このままだと、フレームのレイヤーや使わないレイヤーや背景レイヤーまで取得しちゃいますので、visibleを使うなり、レイヤーセットで仕分けるなり、名前で判別するなり、適宜工夫して「使えるスクリプト」に変えます。

 

動作の様子は、以下のスクリーンショットのごとく。

 

 

*プロンプトの見た目は1行ですが、改行して下に連なっています。

 

*サンプルのスプレッドシートです。実際は、作業用アクションシートとしてのスプレッドシートの見た目になっています。

*実際はドット以下の「.line」をsplitで削除して、項目名だけ書き込んでいます。「hair」「face」というように。

 

 

 

こんな簡単なスクリプトでも、もしレイヤーが20個あって、そのレイヤー名をスプレッドシートなどの伝票に書き写さなければならない時は、手作業と自動処理で格段の差が出ます。自動処理なら、楽な上にミスも皆無です。

 

HTMLのテーブルや、TSVやCSVでよければ、直にファイル出力することまで、Adobeのスクリプトで可能です。

 

スクリプトは覚えて損はないので、思い立った時に、自分の力で覚えましょう。

 

 

 

毎日毎日、線画ばかり描いて、雑事に振る時間があったら、休息に充てたいです。

 

本業をちょいちょい阻害する雑事は、スクリプトの刑に処すのが一番です。

 

 

 


やる、やらない

プログラムを身近な存在にするには、まずはスクリプトを常用して、日々の作業の補助に役立てるのが良いです。

 

After EffectsやPhotoshopなら、ESTK。

 

システム関連ならShellスクリプト。

 

macOS特有ならAppleScript。

 

これだけでも、相当便利になります。Windowsの場合は、何がShellやAppleScriptの代わりになるかは、私はよくわかりませんので調べてみてください。

 

ある程度慣れてきたら、いよいよGUI付きの「ソフトウェア」っぽいものにチャレンジします。macOSだとXcodeという開発環境が無償で提供されており、macOSだけでなく今はむしろiOSの開発環境として活用されています。

 

さすがに、ソフトウェアともなると色々と大変になってきて、起動と終了の動作(初期設定の読み書き)から始まって、ウィンドウを作ってその中にリストボックスやボタンやプログレスバーやプルダウンメニューなどを配置し、それらパーツの動作に関するプログラムを個別に書いて、時にはマウスのイベント(マウスが上に来た、マウスが動いた、マウスのボタンがクリックされた‥‥とか)に対してもプログラムを書き、さらにはApplication Supportの中に自作のライブラリを追加したり、管理者権限を求めたり‥‥と、一気にやることが肥大化します。

 

なので、まずは欲張らずに、日々の作業を地道に軽減してくれるスクリプトから作って、いつでも使えるようにしておきます。デスクトップのメニューから呼び出せるようにしたり、ドックに収納するのも手軽です。

 

*Finderのスクリプトメニューから呼び出す方法

*このブログに画像を掲載する時に活躍するのが、何らかの画像ファイル形式をJPEGに変換するスクリプトです。Photoshopのバッチとかだと大袈裟過ぎますもんネ。

 

 

いまどき、AppleScriptを覚え出すのはナンだなあ‥‥とも思うので、AppleScriptは「窓口」にして、Adobeスクリプト(JavaScriptの独自拡張)やShellスクリプトを実行するのが良いかも知れませんネ。「do script」を使って、AppleScriptは単に窓口に徹して、左から右へと受け渡します。

 

「電力関連を求める」「dpiを求める」ようなスクリプトも上の図にはあります。AdobeスクリプトもShellも必要ない、単純な数式の計算も、スクリプトを作っておくと便利です。

 

ワットとボルトとアンペアの関係なんて、私ら映像制作の人間は覚えてもすぐに記憶が曖昧になりますから、スクリプトを作っておけばいつでも値を確認できます。対話式の簡素なウィンドウで事足りるので、インターフェイスビルダーの助けも不要です。

 

 

 

単純な数値計算といえば。

 

dpiの計算は、スキャンが絡む現場には必須です。ペーパーレスだとピクセル寸法だけでも事足りますが、まだまだ「スキャン解像度」の必要性は高いです。

 

dpiの計算は単純な内容ですが、「インチって何ミリだったっけか」「寸法あたりのピクセル数を求めつつ、インチとミリの変換も混ぜ‥‥」となると、よほど日々頻繁に計算する立場でもない限り、曖昧になりがちです。ゆえに、スクリプトで作っておきます。

 

 

1つ1つのスクリプトは他愛ない内容でも、作って貯めておけば、便利でしょ?

 

こうしたスクリプトをいくつも作る過程で、どんどんプログラムに対する「別の世界のものごと」感が薄れ、日々の作業の単なる1要素まで身近になってきます。

 

それこそ、5000円を三人で割り勘すると、

 

alert(5000/3);

 

‥‥なんていうところからスタートしても良いわけです。

 

今、目の前にあるのは、「プログラムをやる」と「やらない」のシンプルな2択だけ、です。

 

 


0001の作り方

皆さんは、「0001」を作る時、どんな風にしているのだろう。‥‥という疑問が昔からあります。私はスクリプトやプログラムは我流なので、「定番」というのをよく知らないのです。

 

「任意の整数に、任意の桁のゼロを追加する時」に、どんな方法があるのか、他人さまのコードを探して見たことがないので、定番というか、定石がわかりません。プログラムが本職の現場に居たこともないですし。

 

どこかで見かけたのは、1を「1」にキャストして文字数を数えて、if分岐で "0", "00"," 000" のいずれかを加える‥‥という方法でしたが、それはあまりにも面倒なように思います。8桁だったら、if分岐で7回書くことになりますし、ifを使わずに繰り返し文で足りない0を加えるのもちょっと面倒です。

 

改めて探したら、"00"や"000"を足す方法を解説しているページも検索できましたが、やっぱりちょっと面倒ですよネ。

 

 

 

私がもう随分前〜20年前くらいから使っているのは、10に欲しい桁数を冪算(累乗)したものを足す方法です。

 

桁のゼロで揃えたい。

10の乗は、10000。

10000に1を足して、10001。

先頭の桁数をカットすれば、0001の出来上がり。

 

‥‥という感じです。

 

JavaScriptですと、

 

var numberOfDigits=4;
var currentValue=1;

var result=String((Math.pow(10,numberOfDigits))+currentValue).slice(1);

alert(result);

 

‥‥で、以下。

 

JPEG_1.jpg

 

桁数の変更は如何様にでも。

 

例えば、8桁なら‥‥

 

var numberOfDigits=8;
var currentValue=1;

var result=String((Math.pow(10,numberOfDigits))+currentValue).slice(1);

alert(result);

 

JPEG_4.jpg

 

‥‥です。

 

 

 

この我流の方法=「10に桁数で累乗する方法」は、桁固定ではなく、もともとは桁の可変を実現するために考えたものでした。

 

例えば、ファイル総数が130ファイルだった場合は4桁ではなく3桁に、10250だった場合は5桁に‥‥と、状況に応じて変動させたい場面に対応するために、うんうん考えた末に冪算で0を生成する方法に至りました。

 

例えば、総数が72だった場合は、

 

var maxValue=72;
var currentValue=8;

var result=String((Math.pow(10,String(maxValue).length))+currentValue).slice(1);

alert(result);

 

JPEG_2.jpg

 

‥‥と、ちゃんと2ケタになりますし、総数が1200だった場合は、

 

var maxValue=1200;
var currentValue=8;

var result=String((Math.pow(10,String(maxValue).length))+currentValue).slice(1);

alert(result);

 

JPEG_3.jpg

 

‥‥と、ちゃんと4ケタになります。

 

なぜ、この「可変桁数」が必要だったかは、もう20年前のことなので忘れちゃったのですが、ともあれ、"0000"と固定せずに可変でゼロで揃えるニーズに対応するために、POWER()、Math.pow()、 「^」(=AppleScriptでの冪算の記号)を用いてヒネりだしました。

 

自作のAppleScriptによる「リネームスクリプト」でも、このルーチンは使っていまして、

 

JPEG_5.jpg

JPEG_6.jpg

 

‥‥と、4ケタと自動設定が選べるようになっています。

 

 

 

ちなみに、エクセルやGoogleスプレッドシートだと、4桁揃えの場合、

 

TEXT(なんらかの数値,"0000")

 

‥‥で済むという、超便利なTEXT()関数があるようですが‥‥、NumbersにはTEXT()がなーい! なじぇ?

 

 

 

macOSのNumbersでは「TEXT()」関数が無いようなので、以下のごとく。

 

 

RIGHT()関数で、数値を「暗黙の型変換」で文字列として扱いつつ右から4文字取り出す‥‥という方法で、難なくクリア。どんなスクリプトやプログラムにも実践方法はありますネ。

 

 

今回の記事を書くにあたって、皆さんの方法を漁ってたら、「とりあえず0をあらかじめいっぱい付けておいて、「substr」(sliceでも)で簡単に切り出す」方法を紹介していて、感じ入りました。

 

var numberOfDigits=4;
String(100000000+1).substr(9-numberOfDigits);

 

実質、最大8ケタもあれば実用に耐え得るので(映像制作の場合)、9桁固定の方法でも充分対応できますネ。

 

 

 


レイヤー名をナンバリング

ProcreateからPhotoshopに持ち込むと、レイヤー名が文字化けする。

 

‥‥開発元にフィードバックすれば良いのかな。単純な文字コードの問題ですよネ。

 

私は今はもっぱら手短なスクリプトばかり作ってますが、昔はIDE(って、今でも言います? 統合開発環境)を使ってソフトウェアを(稚拙なりにも)作っていたので、文字コードの扱いは厄介でした。テキストストリームの時に文字コードをちゃんと指定しないと、必ずと言って良いほど文字化けしてました。MacOSとOSXの端境期でしたので、SJISとUTFが入り乱れていたのです。

 

昔話はともかく、今すぐにはProcreateは治るまい。

 

まあ、Procreateに限らず、「名称未設定1」,2,3,4,....を1発リネームしたいことはありますよネ。作業の合間にこまめにリネームすれば良いんでしょうけど、矢継ぎ早に頭の中のイメージを描きまくる時はレイヤー名など御構い無しにテンポを落としたくないこともあります。

 

レイヤーフォルダ内のレイヤーのうち、可視状態のものだけをリネームするスクリプトは、あればあったで使い道はありそうです。

 

なので、早速作る。凄く簡単なのを。

 

*注意* スクリプトを実行する場合は、テストファイルで実行して動作を確認してください。あくまで「自己責任」で。

 

alert(main());

 

function main(){
    var ls=app.activeDocument.activeLayer;
    if (ls.typename!="LayerSet"){return ls.name+"は処理対象ではありません";}
    
    var layerList=[];

    for(var i=0;i<ls.layers.length;i++){if(ls.layers[i].visible){layerList.push(ls.layers[i]);}}//処理するレイヤーをリストアップ
    var num=Math.pow(10,String(layerList.length).length);//リネームする総数に応じて桁数を設定
    for (var i=0;i<layerList.length;i++){layerList[i].name=ls.name+"-"+(String(num+layerList.length-i).slice(1));}
    
    return String(layerList.length)+"レイヤーを連番リネームしました";

}

 

 

これを実行すると、こんな状態のが‥‥

 

 

‥‥以下のように、連番で下からリネームされます。

 

 

 

 

処理対象は、レイヤーフォルダの直下にある「レイヤー」(=ArtLayerとLayerSetの見境なし)です。ゆえに、フラット化したレイヤーだけでなく、複数レイヤーをまとめたレイヤーフォルダもそのままリネームします。‥‥たぶん(=試していない)。

 

リネームの基準を、「セル名+4桁連番」に固定したい場合は、以下のようなスクリプトで。

 

4桁固定だと、総数をあらかじめ取得する必要がないので、スクリプトの趣向も変えています。

 

alert(main());

 

function main(){
    var ls=app.activeDocument.activeLayer;
    if (ls.typename!="LayerSet"){return ls.name+"は処理対象ではありません";}

 

    var num=10000;//桁数を4桁に固定
    for (var i=0;i<ls.layers.length;i++){
        var lyr=ls.layers[ls.layers.length-1-i];//下のレイヤーから順番に処理
        if(!lyr.visible){continue;}//処理対象外(不可視)の場合はスキップ
        num++;
        lyr.name=ls.name+""+(String(num).slice(1));
    }
    
    return String(Number(String(num).slice(1)))+"レイヤーを連番リネームしました";
}

 

 

結果は、以下の通りです。

 

 

 

 

visible=可視〜「目玉」のアイコンを消しておけば、連番の処理対象から外れるので、任意のレイヤーのみ連番リネームできます。

 

 

 

 

この作業を、手作業でキーボードで打ち変えていたら、大した内容ではないですが、面倒で地味に時間を消費します。

 

人手だと地味に手間がかかる雑事を、10行程度の命令文を書いてコンピュータで実行するだけで、コンピュータは何の文句も不平も言わずに、超高速で片付けます。まさにコンピュータを使っている「わかりやすい利点」です。

 

 

 

現場の改革の要素は、ビッグなものからスモールなものまで、色々あって悩ましいです。

 

たとえ、将来に作業環境と待遇が改善されても、自分たちが「今欲しい」スクリプトは誰も作ってはくれません。スクリプトを書く知識を得れば、PhotoshopやAfter Effects、macOSやWindowsなどの様々な雑事を自動化できます。

 

でもって、スクリプトが思い通りに動作して、自分の雑事が軽減されると、何とも「愉快」。

 

実はスクリプトやプログラムは、面白いんです。‥‥ピタゴラスイッチのようなものですからネ。

 

 


スクリプトの機能プチ追加

以前作った「Photoshopのレイヤーを順々に書き出す」スクリプトは、実はアニメ作画以外でも結構重宝しています。何かと、Photoshopのレイヤーを個別のファイルに書き出したい場面はあるもの‥‥ですネ。

 

 

 

 

以前載せたこの模式図は、一部省略してありまして、「常時表示するレイヤー」などは図中にありません。

 

実際にスクリプトを作ってみればわかることですが、レイヤーを順次書き出すだけではあまり役に立たないのです。

 

静止画(止め絵)として書き出すレイヤー

レイヤーフォルダにまとめた、イメージシーケンスとして書き出すレイヤー

レイヤーフォルダにまとめているが、静止画として個別に書き出すレイヤー

常時表示するレイヤー

 

最低これらを処理できないと、「線画だけ描いて白地やフレームは他のレイヤーを使いまわし」などの作業省略方法が効きませんもんネ。

 

 

スクリプトは必要に応じて、機能を付け足して強化できます。これが自分でスクリプトを作る醍醐味でもあり、スクリプト・プログラム能力を兼ね備えた作業集団の強みでもあります。

 

現在の仕様では、当座のニーズに合わせて、TGAを書き出す仕様です。それでは、ちょっと限定的‥‥というか、使い道が限られます。

 

なので、TGA、TIFF、PSD(統合した)、JPGくらいの選択肢はあっても良いですよネ。

 

 

リストからプルダウンして選ぶファンクション(1発で呼び出せるヤツ)って、ありませんでしたっけ? ‥‥まあ、ないのか。しょうがないので、windowオブジェクトからいちいち作りました。う〜ん、コードでGUIを記述するのは面倒。

 

AppleScriptなら「choose from list」で済むんですけどネ。ESTKのエディタだけでなく、インターフェイスビルダーが欲しい。

 

どうせなら、ファイル形式だけでなく、書き出し場所の指定も‥‥とか、機能を増やしたくなりますが、前回指定した項目や場所を覚えておくにはプリファレンスの仕組みも必要だし、何だか地味に規模が広がっていくので、欲張りはナシに。

 

でもまあ、この程度のスクリプトでも、無いよりはあったほうが百倍マシです。実際、手作業でレイヤーを書き出してたら、日が暮れます。

 

 

どんなにソフトウェアが充実しても、スクリプトの必要性は全く薄れないでしょう。

 

絵を描くのは、ラスターだろうがベクターだろうが、線を1本1本、手作業で然るべし。そこを放棄したら、絵描きではなくなります。絵描きを名乗れない。

 

でも、ファイルの書き出しを1ファイルごと手作業ではなく自動処理しても、絵描きでなくなるわけがないです。むしろ、そういう手間はどんどん自動化して、もっと絵に精進するか、自動化で浮いた時間は帰宅して明日のために寝ましょう。

 

目下の課題は、アニメーターをはじめとした作業集団の内部に、どうやってスクリプト修得者を獲得するか‥‥です。皆、「難しいから」とか言って、やらんもんなあ‥‥。時間の有無以前に、敬遠したり、嫌がったりするでしょ。時間があっても、プログラムは覚えない人が圧倒的多数だもんね。

 

う〜ん。絶対に必要なんだけどネ。内部には。

 

 


再帰処理

スクリプトを他人に説明する時、一番説明しにくいのは、再帰処理です。「自分自身を呼び出す処理」とか言っても、即座には何のことやらイメージできないですもんネ。

 

前回記事のレイヤーをファイルとして書き出す処理も、「もしレイヤーがレイヤーフォルダだったら、レイヤーフォルダの中身に潜って、同じ処理を繰り返す」再帰関数を作って処理していましたが、スクリプト文の引用を避けたのは、再帰関数の説明が長くなりそうだったからです。

 

レイヤーフォルダは、Photoshopの内部では「LayerSet」と呼ばれています。typename(当該項目がどんな種別かを判別する文字列)を調べると、普通の画像レイヤー(背景レイヤーやテキストレイヤーも含む)は「ArtLayer」、レイヤーフォルダは「LayerSet」という文字列が返ります。もし処理するレイヤーのtypenameが「LayerSet」だったら、中身に潜って処理を続行しないと、1階層しか処理できないポンコツスクリプトになってしまいます。

 

かと言って、前回のニーズだと、「レイヤーフォルダ階層の底まで潜ると潜り過ぎ」という条件がありましたので、「セルごとの連番レイヤーフォルダなら潜る。そうでない場合は潜らない。」というIF分岐を設けました。IF分岐はレイヤーフォルダ名で判別しました。

 

 

 

再帰処理は、私がスクリプトを覚え始めた20年前の初心の頃に、ウンウン唸りながら理解を進めました。まあ、普通の日常に、再帰処理なんて意識することはないので、もしかしたら「オブジェクト指向」よりも解りにくいかも知れません。オブジェクト指向的アプローチは、日々の料理のバリエーション展開など、身の回りに豊富ですが、再帰ルーチンは日常ではイメージしにくいです。

 

例えば、レイヤーフォルダに含まれるアートレイヤーの数を数えるスクリプトを考えた場合、レイヤーフォルダの階層が3階層までだったら、以下のように3回「for」ループで中身を総当たりで潜って処理できます‥‥が、まあ、こういうやり方は逆に大変です。

 

var artLayerCount=0;
for (var i=0;i<app.activeDocument.layers.length;i++){//第1階層
    if(app.activeDocument.layers[i].typename=="LayerSet"){
        for (var ii=0;ii<app.activeDocument.layers[i].layers.length;ii++){//第2階層
            if(app.activeDocument.layers[i].layers[ii].typename=="LayerSet"){
                for (var iii=0;iii<app.activeDocument.layers[i].layers[ii].layers.length;iii++){//第3階層〜これ以上潜らない
                    if(app.activeDocument.layers[i].layers[ii].layers[iii].typename=="ArtLayer"){artLayerCount++;}
                }
            }else{
                if(app.activeDocument.layers[i].layers[ii].typename=="ArtLayer"){artLayerCount++;}
            }
        }
    }else{
        if(app.activeDocument.layers[i].typename=="ArtLayer"){artLayerCount++;}
    }

}
alert(artLayerCount);

 

 

最大3階層までのレイヤーフォルダの中身のアートレイヤーをカウントして‥‥

 

 

‥‥と、一応は正確なレイヤー数はカウントしてくれます。

 

しかし、この3階層分の入れ子を直に文で書いてしまうと、正直、「今、何階層目か」、文を書いてて解らなくなります。非常に煩わしくて面倒です。ループを回す「i」変数を ii iii と切り替えるくだりは、煩雑そのもので書いてて混乱します。

 

書くのが面倒で読みにくい深い構造で、メンテナンス性(後で書き換えるなど)が最悪なのに、第4階層以下は潜ってくれず、処理してくれません。大変なわりに機能がショボい。

 

第4階層以上は潜れないので、

 

 

‥‥のような深い階層を持つレイヤー構造に対応できず、あくまで第3階層までしかカウントできません。

 

 

 

なので、再帰関数の出番。

 

var artLayerCount=0;
alert(artLayerCounter(app.activeDocument.layers,artLayerCount));

 

function artLayerCounter(_layers,_count){
    for (var i=0;i<_layers.length;i++){
        if(_layers[i].typename=="LayerSet"){
            _count=
artLayerCounter(_layers[i].layers,_count);//自分自身を呼びだす
        }else{
            if(_layers[i].typename=="ArtLayer"){_count++;}
        }
    }
    return _count;
}

 

 

「artLayerCounter()」という関数の中で、処理対象のレイヤーの種別がレイヤーフォルダだった場合は、関数自身にレイヤーフォルダの中身を入れ子で投げ込んでいます。

 

この構造ならば、階層が10階層だろうが、延々と中に潜って処理します。

 

しかも、文字数も少なく、見た目の階層は1階層なので、メンテナンス性も高いです。

 

 

 

 

ちゃんと、テキストレイヤー、画像レイヤー、背景レイヤーの合計を正確にカウントできています。

 

 

 

再帰処理を使わないと、文が長く読みにくくなる上に、処理対象の階層が深くなると機能は限定されて、いいとこなし‥‥です。

 

私は、一回でも再帰的な入れ子の処理が出てきた時は、迷わず再帰処理を使います。「潜るのは一度きりで今回限り」とは限らない事例が多いからです。後日に、もっと階層を潜れるニーズが発生した時に、再帰処理であらかじめ組み立てておけば、簡単な手直しで対応できます。

 

Photoshopに限らず、After Effectsのプリコンポーズした入れ子にも使えますし、OSのフォルダ階層にも応用できます。再帰処理を使えば、どんなに深いフォルダのファイルでも総当たりで一覧を作成できますから、過去作品のディスクアーカイブの内容一覧にも使えますネ。

 

再帰処理は、プログラムを覚えて色々な自動処理のパワーを実感する中で、「これは人力では不可能だ」と特に感じるものです。

 

アニメ制作における様々な事務的な雑事は、まさに再帰的な処理、反復処理の連続ですから、コンピュータを「絵や映像を作る時だけ」でなく、「作る前と作った後」にも活用して、全体的な作業効率を高めましょう。

 

アニメの映像そのものを作るのに精魂を使い果たした後で、事務的な処理にさらに1〜2時間居残りで作業‥‥なんて、できるだけ回避したいですもんネ。

 

 


原画PSDファイルから書き出し

Photoshop形式の原画上がり=各セルの連番をまとめたレイヤーフォルダやレイアウトやフレーム指示のレイヤーなどを、あたかもタイムシートに挟んだ原画上がり一式として別ファイル出力するPhotoshopのスクリプトを今日必要に迫られて作りました。前々から作っておくべき!‥‥と考えていたのですが、ようやく重い腰を上げて作った次第です。

 

今回作ったのはコレ。

 

 

書き出すファイル形式は、当座の都合でTargaにしていますが、レイヤーなしのTIFFでもPSDでも可能です。絵が荒れるのでJPEGは使う予定はないですが、JPEGでもGIFでもPNGでも可能です。アルファチャンネルはファイル形式と状況によって適宜。

 

そして、(いつ作るかはニーズに応じて未定ですが)コレも用意しておくと、特定のプラットフォームやソフトウェアに縛られず、ファイルとレイヤーの行き来が可能になりましょう。

 

 

もはや、PSDファイルのレイヤー構造は、AdobeのPhotoshopでの使用に限定したものではなく、「レイヤー付き画像フォーマットといえばPSD」というくらい各所で普及していますから(ProcreateでもPhotoshopのレイヤー構造を保ったまま読み書き可能)、この2つのスクリプトは便利に使えると思います。

 

スクリプト自体には何の難しいところもないです。レイヤーの表示(=visible)を出力の基準にして、レイヤーの種別(ArtLayerやLayerSet)に応じて、当該のファイルフォーマットで複製保存するだけです。まあ、「常時表示するレイヤー」とかをちゃんと見分ける仕込みは必要ですが、基本的には難しいことはないです。

 

難しいのは、そのPhotoshopの「レイヤー構造の成り立ち」のほうです。

 

階層の深さの規定は、絶対に必要です。また、レイヤー名に基づいて出力するので、レイヤー名とその親フォルダの命名規則は極めて重要です。

 

でも、そういう部分が一番ルーズになるものです。人間が介在する部分が、一番「揺れ」ます。

 

なので、当座はスクリプト処理の都合も含めて、以下のように定めました。

 

  • スクリプトが掘る階層は、レイヤーフォルダの第1階層まで。
  • 静止画としてのレイヤーフォルダと連番格納のレイヤーフォルダは名前で判別する。
  • 連番レイヤーは、親フォルダ名とレイヤー名を連結してセルのファイル名とする。
  • 常時表示のレイヤーはレイヤー名先頭に判別文字を付与する。

 

 

とはいうものの、私のメインはあくまでCO/KFアニメーションなので、「従来作画のタブレット化・データ化への関与」はやんわりと距離を置くべきと考えており、上記程度の決め事で様子見です。

 

 

 

「デジタル作画」のここらへんの決まりって、誰か決める人、いないのかな‥‥。「デジタル作画」を自分のメインにしていこうと思っている人たちが、自分たちで決めていくのが良いと思います。私がフガフガ鼻息荒くして言う立場じゃないです。

 

一方、CO/KFアニメーションでの線画作業については、徐々にガイドラインを構築しつつあります。レイヤー名の命名規則も、

 

object.line

object.shadow.region

object.shadow.line

 

‥‥など、何度かの紆余曲折を経て、固まりつつあります。コンピュータで用いる規則ですから、プログラム・スクリプトでも処理しやすいように考えています。

 

 

 

Photoshopのスクリプトは久々に書きましたが、After Effectsとは似ているようでちょいちょい異なるので、多少混乱しました。

 

「layers」って、リファレンスには「The collection of layer objects」って書いてありますが、After Effectsでは「collection」は「コレクションオブジェクト」といいまして、

 

インデックス番号1から始まり()で呼び出す集合

 

‥‥なのに、Photoshopでは、

 

インデックス番号0から始まり [ ] で呼び出す配列

 

‥‥なのは、当初混乱しました。

 

また、Targaを書き出す際に用いる「TargaSaveOptions」のプロパティに、

 

resolution :The number of bits per pixel

 

‥‥があって、「タルガって解像度があったんか!」と一瞬驚きましたが、よく読むと、

 

1ピクセルあたりのビット数

 

‥‥で、初期値は「TargaBitsPerPixels.TWENTYFOUR」=24bitとありますから、いわゆるピクセルの色深度(各チャンネルの深度)のことですネ。1ピクセルあたりに使えるビット数という定義なのか、depthとは言わんのネ。

 

スクリプトの内容は、普通なら手作業でレイヤーのオンオフを切り替えて別名保存するのを、自動処理するものなので、何の特別な技も必要ないです。ただ、段取りが面倒なだけ‥‥です。

 

スクリプト動作中は、Photoshopが固まったようになるので、スクリプトが動いているんだかエラー停止しているのかイマイチ判別ができませんが、Finder上でフォルダが自動で作成されて、その中にファイルがどんどん増えていくのを見ながら、動作を確認しました。

 

 

 

なんとなく手作業のまま処理して、結構な時間を消費していた作業が自動化できました。今回はTarga書き出し版ですが、TIFF書き出し版(dpi〜解像度をもつ)も一部変更するだけで作れます。

 

必要なマニュアルは、以下のPDFにて。

 

Photoshop CC JavaScript Reference

 

フォルダなどファイルシステム管轄の操作は「JAVASCRIPT TOOLS GUIDE」(ESTKのSDKフォルダの中にあります)で「Folderオブジェクト」の項を読めば解ります。

 

 

 

 


sips

macOSには「Image Events」という裏方のアプリケーションがあって、AppleScriptからも利用することができます。以下はその機能の一部です。

 

save v : Save an image to a file in one of various formats

save specifier : the object for the command

[as BMP/‌JPEG/‌JPEG2/‌PICT/‌PNG/‌PSD/‌QuickTime Image/‌TIFF] : file type in which to save the image ( default is to make no change )

[icon boolean] : Shall an icon be added? ( default is false )

[in text] : file path in which to save the image, in HFS or POSIX form

[PackBits boolean] : Are the bytes to be compressed with PackBits? ( default is false, applies only to TIFF )

[with compression level high/‌low/‌medium] : specifies the compression level of the resultant file ( applies only to JPEG )

 

rotate v : Rotate an image

rotate specifier : the object for the command

to angle real : rotate using an angle

 

scale v : Scale an image

scale specifier : the object for the command

[by factor real] : scale using a scalefactor

[to size integer] : scale using a max width/length

 

 

つまり、Image Eventsを使って、AppleScriptをユーザーの窓口にすれば、ちょっとした画像形式変換ソフトが作れるわけです。書き出せる形式は、上の通り、「BMP JPEG JPEG2 PICT PNG PSD QuickTime Image TIFF」と、とりあえずは困らないくらいの幅広さはあります。画像の回転やサイズ変更、切り取りも可能です。‥‥PICTはさすがにもう使わんけど。

 

AppleScriptに慣れない場合は、シェル経由の「sips」コマンドでも同じことが可能です。AppleScriptとImage Eventsの組み合わせだととかくスクリプト文が長くなりがちですが、シェルならば多少冗長にはなりますが1行で済みます。

 

まずは「man sips」でマニュアルに目を通してみれば、結構な画像変換ができることがわかります。「sips -h」や「sips -H」でも、色々なオプションが確認できます。‥‥文量が多いので、ここではあえて引用しませんが。

 

処理できる内容を見てみると、どうもImage Eventsとsipsは同じもの‥‥なんでしょうかね。その辺の内部事情は知らないので何とも言えませんが、できることは共通しています。

*ただ、Image Eventsの方の用語辞書をみると(上記の)、Targaが抜けてますね。書き忘れ?

 

 

 

例えば、中に144ファイルのPSD連番が入ったフォルダを丸ごとJPEGに変換する‥‥なんていうのも1行コマンドで簡単に、しかも144ファイルの2KサイズPSD程度なら数秒で処理できます。

 

sips -s format jpeg PSD連番フォルダパス/*.psd --out 書き出すフォルダパス

 

JPEGの圧縮率なども指定可能ですが、まずは簡単な1文にて。

 

フォルダの中身はもう自分で承知しているから大丈夫‥‥という人は、

 

sips -s format jpeg PSD連番フォルダパス/* --out 書き出すフォルダパス

 

‥‥という書き方でもOKです。/* はフォルダの中身全部‥‥という意味です。

 

アニメ現場ではおなじみのTargaも書き出せます。

 

sips -s format tga PSD連番フォルダパス/* --out 書き出すフォルダパス

 

ただし、Targaで書き出すと、解像度は72dpi‥‥というか「値無し」になります。アニメ業界でこれだけ常用されているのに意外に思いますが、Targaにはもともと「平方あたりの画素・ドットの数」という概念がありません。ビデオに特化したフォーマットだったらしく、印刷とか実物スキャンは全く考慮されていないのです。

*ただ、Targaには「開発者が使えるデータ領域」があるので、そこに独自拡張で解像度を記録することはできると思います。でもまあ、あくまで独自拡張なので一般では通用しないですけどネ。

 

 

コマンドは使い続けていないとすぐに忘れてしまいがちなので、そんな時はAppleScriptと組み合わせて、ドラッグ&ドロップのJPEG書き出しドロップレットを作ってしまいましょう。

 

処理するフォルダと新作するフォルダをAppleScriptのFinder命令で指定して、POSIX Path(スラッシュ区切りのUNIX形式のパス)に変換して、シェルに渡します。

 

どうせなので、アプレットとドロップレット両方で動作するアプリケーションにします。

 

on run

    tell application "Finder"

        set importFolder to choose folder with prompt "変換するフォルダを指定"

        set exportFolder to choose folder with prompt "書き出すフォルダを指定"

    end tell

    my saveAsJPEG(importFolder as Unicode text, exportFolder as Unicode text)

end run

 

on open theItems

    repeat with theItem in theItems

        set importItem to theItem as Unicode text

        tell application "Finder"

            if folder importItem exists then

                make new folder at container of theItem with properties {name:((name of theItem) as Unicode text) & "-JPEG"}

                set exportItem to result as Unicode text

            else

                set exportItem to ((characters 1 thru -((length of ((name extension of theItem) as Unicode text)) + 2) of importItem) as Unicode text) & ".jpg"

            end if

        end tell

        my saveAsJPEG(importItem, exportItem)

    end repeat

end open

 

to saveAsJPEG(_i, _e)

    set _all to ""

    if character -1 of _i is ":" then set _all to "*"

    do shell script "sips -s format jpeg " & (quoted form of POSIX path of (_i as Unicode text)) & _all & " --out " & (quoted form of POSIX path of (_e as Unicode text))

end saveAsJPEG

 

 

このスクリプト文にテキトーな名前をつけてアプリケーション形式で保存すれば、ダブルクリックでもドラッグ&ドロップでも動作する、自作のmacOS用アプリの完成です。

 

 

シェルに投げるまでのお膳立てをAppleScriptとFinderでおこなう仕組みですので、実は肝心の「画像形式変換」の部分は1行のみです。アプリを作るのは前置きが長いのです‥‥って、これでもかなり短い部類です。

 

ブログにちょろっとペーストできるほど短い文で済んでいるのは、なによりも「エラー対策」をほぼ全部端折っているからです。もし、同階層に同じ名前のフォルダやJPEGファイルがあった場合はエラーで止まりますし、アイテムを分別する条件分岐もアマアマです。テキストファイルをドロップしても動作を開始してしまう構造です。

 

でも、作った本人だけが使う分には問題はありません。自分で文を書いて作ったがゆえに、隅々まで処理内容を知っているので、うっかりでもない限り、エラーを自ら呼び込む使い方をしないからです。

 

 

まあ、2019年現在にAppleScriptを覚えよう!‥‥なんて薦めませんが、何かしらのプログラム・スクリプト言語を日頃から手に馴染ませておくことで、自分で使うための自分専用アプリを、思いついた時、もしくは必要に迫られた時に、サクッと作れるのは、コンピュータを使う醍醐味・利点でもあります。

 

‥‥そういえば、sipsはTargaも書き出せますから、画像連番を一気にTargaに変換するのも作っておきましょう。

 

on run

    tell application "Finder"

        set importFolder to choose folder with prompt "変換するフォルダを指定"

        set exportFolder to choose folder with prompt "書き出すフォルダを指定"

    end tell

    my saveAsTarga(importFolder as Unicode text, exportFolder as Unicode text)

end run

 

on open theItems

    repeat with theItem in theItems

        set importItem to theItem as Unicode text

        tell application "Finder"

            if folder importItem exists then

                make new folder at container of theItem with properties {name:((name of theItem) as Unicode text) & "-TARGA"}

                set exportItem to result as Unicode text

            else

                set exportItem to ((characters 1 thru -((length of ((name extension of theItem) as Unicode text)) + 2) of importItem) as Unicode text) & ".tga"

            end if

        end tell

        my saveAsTarga(importItem, exportItem)

    end repeat

end open

 

to saveAsTarga(_i, _e)

    set _all to ""

    if character -1 of _i is ":" then set _all to "*"

    do shell script "sips -s format tga " & (quoted form of POSIX path of (_i as Unicode text)) & _all & " --out " & (quoted form of POSIX path of (_e as Unicode text))

end saveAsTarga

 

 

数カ所変更するだけで、主要な画像形式のファイルを連番丸ごと変換するmacOSアプリの出来上がりです。

 

 

 

ちなみに、今回は画像保存時のオプションを一切省いていますが、JPEGなら圧縮率とかTIFFならLZW圧縮の有無とかを指定できます。拡大縮小や、回転(現場ではあまり必要ないけど)なども処理できます。

 

 


604800

Mac版のESTKはひっそりと提供が終了しており、昔のフォルダから移植して使っている状態です。

 

去年の終わり頃に、ESTKでアラートが出て動作しないトラブルがありましたが、私は最近まで対処しないままでした。絵を描く方がメインになって、ESTKは使う機会が減っていたので。

 

ESTKのappのパッケージを掘っていって「604800000」を「604800」に書き換えれば終了‥‥なのですが(説明を端折ってスミマセン。詳細はネットで検索してください。)、あくまで当座ローカルにあるESTK.appが書き換わっただけで、他の環境でも同じことをせねばなりません。

 

う〜ん。覚えてられない。階層も深いし。

 

なので、さくっとスクリプト。AppleScriptで動作する「6048自動書き換えスクリプト」です。このスクリプトをクラウドに保存しておいて、未処置のESTKと遭遇した場合に実行すれば、どこにいても解決できます。

 

 

tell application "Finder"

    set estk to choose file with prompt "ExtendScript Toolkit.appを指定してください"

    if (name of estk) is not "ExtendScript Toolkit.app" then

        beep

        return false

    end if

    set targetFile to (estk as Unicode text) & "Contents:SharedSupport:Required:cdic:11BTBackend.jsx"

end tell

do shell script "sed -i'-bak' -e 's/604800000/604800/' " & (quoted form of POSIX path of targetFile)

 

 

最後の1行はAppleScriptというよりは、sed。

 

最後の1行が肝心の部分です。それより前はESTKを指定するまでの前置きです。

 

sedは初めて使ってみましたが、便利ですネ。

 

一応バックアップを取った後で書き換えています。バックアップがiオプションでできるのも便利ですネ。AppleScriptでは全部自分でサブルーチンを作らねばならんスから。

 

AppleScriptは、シェルコマンドも実行できるし、Adobeのスクリプトも実行できるので、今でも現役です。今から大掛かりな新しい何かをAppleScriptで作ろうとは思いませんが、文房具のテープやカッターくらいの気持ちで気軽に使えるのが今でも現役の理由です。

 

 

 

 


ESTKのスクリプトをAppleScriptに埋め込む

前々回のブログで、せっかく、それなりに高速処理のリネームスクリプトができたので、ESTKエディタからの実行だけでなく、AppleScriptでGUIをくっつけて、気軽にドラッグ&ドロップでも処理できるようにしました。

 

アプレットでもドロップレットでも動作するように、「on open」と「on run」を併用しています。

 

macOSのアプリケーションフォルダにある「スクリプトエディタ」を起動して、おもむろにAppleScriptとESTKの合体コードを作ります。

 

 

property defaultItem : false

 

on open theItems

    my main(theItems)

end open

 

on run

    tell application "Finder" to if defaultItem is false or not (defaultItem exists) then set defaultItem to home as alias

    set res to choose folder with prompt "処理するフォルダを選択してください." default location defaultItem with multiple selections allowed

    tell application "Finder" to set defaultItem to (parent of (item 1 of res)) as alias

    my main(res)

end run

 

to main(_folders)

    set errorText to {"フォルダ指定が不正です", "フォルダが空です"}

    set errorLog to ""

    repeat with _folder in _folders

        set res to my runAdobeScript(_folder as Unicode text)

        activate

        if res as integer > 0 then

            tell application "Finder" to set folderName to name of _folder

            set errorLog to errorLog & folderName & tab & res & tab & (item (res as integer) of errorText) & return

        end if

    end repeat

    activate

    if errorLog is "" then

        display dialog "処理が正常に終了しました" with icon 1

    else

        display dialog "エラーが発生しました

下記のエラーログを確認してください" with icon caution default answer errorLog

    end if

end main

 

to runAdobeScript(folder_path)

    tell application "Adobe After Effects CC 2018"

        DoScript "app.exitCode=0;

_1801_RENAME_RE=new RegExp('[_-]*[0-9]+¥¥.[A-Za-z0-9]{2,}');

app.exitCode=main();

 

function main(){

    var theFolder=new Folder('" & folder_path & "');

    if(!theFolder){return 1;}

    var theFiles=theFolder.getFiles();

    if(theFiles.length<1){return 2;}

    for(var i=0;i<theFiles.length;i++){

        var reMatch=theFiles[i].name.match(_1801_RENAME_RE);

        if(reMatch&&theFiles[i].name.match(/^[A-Za-z0-9]/)){

            theFiles[i].rename(theFolder.name+String(reMatch));

        }

    }

    return 0;

}"

    end tell

end runAdobeScript

*前回のバックスラッシュの文字化けを防止するために、ARIELフォントにしてみました。‥‥けど、やっぱり、¥になっちゃった。

*このスクリプトのコードはサンプルです。実際に使用する際は、自己責任でお願いします。

*あ‥‥そういえば、パスに日本語(2バイト文字)が混ざっている場合の処理は盛り込まれていないです。忘れてました。なので、その辺はよしなに。

 

書いたら、アプリケーション形式で保存すれば、ドラッグ&ドロップで動作する、小さなアプリケーションみたいなのが出来上がります。

 

 

 

実際に動作している映像はこちら。毎度のGIFアニメですまんす。

 

 

 

フォルダの名前で、内包するファイルの名前をリネームしている様子が、小さくて見にくいですが、なんとか伝わると思います。

 

合計500ファイル以上あるリネームを瞬時に処理します。フォルダを複数処理すると、ウィンドウの更新に時間がかかるようですが、それでも数秒の処理です。

 

 

‥‥で。

 

ここまで作ってなんですが、「この方法はないな‥‥」と思いました。

 

ESTKのエディタからであれば、実行ボタンで処理を実行できます。しかし、ESTKエディタではなく、AppleScriptからですと、なんらかの「ホストアプリケーション」〜つまり、実行する環境が必要になります。

 

なので、上述のAppleScriptのコード文では「After Effects」を呼び出していますが‥‥

 

そりゃないでしょ。

 

After Effectsの機能は全く使わず、リネームの実行環境としてのみ使うためにAfter Effectsを起動するなんて、スーパーへ買い物に行くのにヘリコプターを飛ばすようなもんです。段取りが大袈裟すぎます。

 

 

まあ、なので、結論としては、

 

ESTKのスクリプトはjsxで保存して、After EffectsやPhotoshopを起動している時に、メニューから呼び出す

 

‥‥のが、使い方の基本ですかね。やっぱり。

 

リネームのため「だけ」に、PhotoshopやAfter Effectsを起動するのは‥‥さすがに、ないわ。

 

 

 

まあでも、せっかく作ったので、なんかあった時に使ってみるかも、です。

 

どうせ、After EffectsやPhotoshopは起動しっぱなしだし。

 

 

 



calendar

S M T W T F S
    123
45678910
11121314151617
18192021222324
25262728293031
<< August 2019 >>

selected entries

categories

archives

profile

search this site.

others

mobile

qrcode

powered

無料ブログ作成サービス JUGEM