忍者ブログ

ぼんぷろぐ

InDesignとかイラレとかのスクリプトよもやま話

新しいブログに引っ越しました。

こちらのブログはもう更新しませんが、コメント欄は生きてますので疑問、ご指摘などありましたらどうぞ。

[イラレ]
上端からの距離に比例した移動量で下に動かすスクリプト

ご要望があったので、左端からの距離に比例した移動量で右に動かすスクリプトの「上から下」版を作りました。実は「左から右」版作ったときにこっちもほぼ完成してたんですが。

使い方は「左から右」版の方を見てくださーい

ダウンロード


ver1.0 - 2021/01/12

動いてるところ

PR

[イラレ]
「Bridgeで参照」を使い物にする イラレ編

ファイルメニューの「Bridgeで参照」、Bridgeが起動するだけで何も参照してくれないんだけど、せめて今開いてるドキュメントくらい参照してくれるようにならんかなー

っていう思いで前回、InDesignの「Bridgeで参照」を改造する話をやったんですが、今回はそのイラレ編です。

しかしメニューコマンドの処理をスクリプトで書き換えるなんて大それたことをさせてくれるのはInDesignくらいのもので、イラレやフォトショのスクリプトではそこまでの自由度はありません。どうしよう。



ExtendScriptにはBridgeTalkという、Adobeアプリ間でスクリプトを送り合えるしくみがあるんですが、イラレのファイルメニューの『Bridgeで参照』にはBridgeTalkが使われています。

具体的には、『Bridgeで参照』を実行すると、次のコードがBridgeにBridgeTalkを介して送られています。

app.bringToFront();
if (app.documents.length == 0) app.browseTo();
else app.document.thumbnail = new Thumbnail();

これをコードAと呼ぶことにしましょう。

ちなみにこのコード、ESTKからBridgeを対象に実行すると、なんとエラーが出ます。
3行目の new Thumbnail() が引数なしを許容してないんですね。
BridgeTalkから実行した場合もエラーになるんですが、「BridgeTalk内のエラーはアラートも何も表示されず、ただそこでスクリプトの実行が終わるだけ」という仕様と、1行目の app.bringToFront(); だけでBridgeを最前面に表示するという仕事が完了していることにより、これまで誰にもばれずにエラーを出し続けてきたんだと思われます。

それはともかくとして、『Bridgeで参照』を実行したときの通常の処理はこんなんです。

イラレで『Bridgeで参照』を実行

BridgeTalkでコードAがイラレからBridgeに送信される

Bridge上のBridgeTalk.onReceive関数がコードAを受け取る

onReceive関数内でコードAがevalされる

app.bringToFront();が実行された後、エラーが出て終わり

重要なのは、BridgeTalkで送られたコードというのは無条件で実行されるわけではなくて、BridgeTalk.onReceiveによって処理されるという点です。
んでBridgeTalk.onReceiveってどんな関数なのって言うと、ESTKからBridgeを対象に BridgeTalk.onReceive.toSource() してみると分かるんですが、次のようなコードです。

(function( msg ) {
 	app.lastSender = msg.sender;
 	app.displayDialogs = 'all';
 	var retval = eval( '$.level = 0; app.synchronousMode = false;\n' + msg.body );
 	app.displayDialogs = 'all';
 	app.synchronousMode = false;
 	return retval;
})

送られてきたコードを実行しているのは4行目のevalです。msg.bodyにコードが入っています。

他の行も見てみると、2行目はBridgeTalkを送りつけてきたアプリの名前をapp.lastSenderに代入しています。これによりファイルメニューの「〇〇に戻る」の〇〇がそのアプリになります。
イラレから「Bridgeで参照」した直後は「Illustratorに戻る」、フォトショから「Bridgeで参照」した直後は「PhotoShopに戻る」に変化するのはこういう仕組みだったんですね。


でー、このBridgeTalk.onReceiveなんですが、実は書き換え可です。
たとえば、送られてきたコードがコードAに完全に一致する場合のみ特別な処理を行い、それ以外の場合はデフォルトのBridgeTalk.onReceiveと同じ処理をする、ということもできちゃうわけです。
ここまでの説明は、「BridgeのBridgeTalk.onReceiveを書き換えることで、イラレの『Bridgeで参照』の挙動を変えてやろう」という企みを分かっていただくためのものだったのでした。




てことで、イラレの「Bridgeで参照」を、現在のドキュメントを参照するようにするBridge用スタートアップスクリプトです。

//    イラレの「Bridgeで参照」を、現在のドキュメントを参照するようにするBridge用スタートアップスクリプト
var aiBridgeDeSansho1="app.bringToFront();if%20(app.documents.length%20==%200)%20%20%20%20app.browseTo();else%20%20%20%20app.document.thumbnail%20=%20new%20Thumbnail();";
var aiBridgeDeSansho2="app.document.thumbnail%20=%20new%20Thumbnail();";//Bridgeが起動してないときはこっちになるっぽい

var btOnReceive2=(function(msg) {
    var body2=encodeURI(msg.body);
    if(msg.sender.slice(0,11)=="illustrator" && (body2==aiBridgeDeSansho1 || body2==aiBridgeDeSansho2)){
        app.bringToFront();
        app.lastSender = msg.sender;
        var bt=new BridgeTalk;
        bt.target=msg.sender;
        bt.body="app.documents.length==0?0:app.activeDocument.fullName";
        bt.onResult=function(res){
            if(res.body=="" || res.body=="0")return;
            app.document.thumbnail=new Thumbnail(File(res.body));
        }
        bt.send();
        return;
    }
    app.lastSender = msg.sender;
    app.displayDialogs = 'all';
    var retval = eval('$.level = 0; app.synchronousMode = false;\n' + msg.body);
    app.displayDialogs = 'all';
    app.synchronousMode = false;
    return retval;
});

BridgeTalk.onReceive=btOnReceive2;
BridgeTalk.watch("onReceive",function(){return btOnReceive2});//スタートアップスクリプトの後にonReceiveが初期化されるのを防ぐ

インストール方法

①Bridgeを開いて、環境設定からスタートアップスクリプトの『マイスタートアップスクリプトを表示』をクリック
②Startup Scriptsフォルダが開くので、ここに上記スクリプトを拡張子.jsxで保存したものを置きます
③Bridgeを再起動すると「新しい機能を有効にしますか?」みたいなダイアログが出るのでOKを押します

これでイラレから「Bridgeで参照」したとき、現在の(最前面の)ドキュメントがBridge上で選択されるようになってるはずです。(ダメだったら教えてください)


関連記事

イラレ&Bridgeの昔書いたネタ(超便利だと思うんだけど特に褒められなった…)
イラレの画像再リンクをBridgeから行うためのスクリプトをつくったー

[イラレ]
Illustrator Script: Move to the right in proportion to the distance from the left end.

ご要望があったので、昔公開したスクリプトを1つ英訳しました。


You can run this script when multiple items or one group are selected in Illustrator CS6 or later.

Move the slider to move each selected item to the right by a distance proportional to the distance from the left end of the selected items.

[Download]

About dialog



Distance : Moving distance (Original distance from the left end = 100)
Width : Overall width of selected items
Right end : X coordinate of the right end

Movie


[イラレ]
イラレスクリプトで特定の座標を中心にした回転

イラレスクリプトの座標系は、右がx軸の+方向、上がy軸の+方向で、原点はアートボードを特に動かしてなければ1つ目のアートボード左上になります。単位はpt。

なので座標 (100,100) はこのあたり。


で、今回はこの (100,100) を中心に選択アイテムを30°回転するというスクリプトを書いてみようという話です。


ページアイテムを回転するメソッドといえば rotate ですが、これは6番目の引数で回転の中心を指定できます。選べるのは以下の10個。

Transformation.DOCUMENTORIGIN
Transformation.TOPLEFT
Transformation.LEFT
Transformation.BOTTOMLEFT
Transformation.TOP
Transformation.CENTER
Transformation.BOTTOM
Transformation.TOPRIGHT
Transformation.RIGHT
Transformation.BOTTOMRIGHT

残念ながら中心の座標を数値で指定する選択肢はありません。
しかしDOCUMENTORIGIN、つまり座標でいえば (0,0) なら選ぶことができます。

そこでこう考えます。

(-100,-100) ほど移動

(0,0) を中心に30°回転

(+100,+100) ほど移動

をすれば、点 (100,100) を中心に30°回転したのと同じじゃん!と。

移動のメソッドtranslateと回転のメソッドrotateを使えば次のように書くことができます。

var sel=app.activeDocument.selection;
for(var i=0;i<sel.length;i++){
    sel[i].translate(-100,-100);
    sel[i].rotate(30,true,true,true,true,Transformation.DOCUMENTORIGIN);
    sel[i].translate(100,100);
}

これでできあがり、でもいいんですが、
なんかアイテム1つにつき移動→回転→移動と3つもメソッド使ってると、大量のアイテムを処理するとき重くなるかもしれないし、なんかもうちょっと良い書き方はないかしら、と考えてみます。



イラレのPageItemには transform というメソッドがあります。
これはTransformationMatrix(変形行列、2次元アフィン行列)という、次式のような6つの変数を持つ行列を使って変形を行うものです。

ここでいう変形とは、回転、移動、拡大縮小(縦横比を保持しないものも含む)、シアー、およびそれらの組み合わせです。
たとえば「原点を中心にθ回転」の変形行列は

となります。
ある点(x,y)を「原点を中心にθ回転」した点(x',y')は、行列とベクトルの掛け算を使って、


で求めることができます。

しかし、こんな式は覚えなくても大丈夫です。
Illustratorスクリプトには便利な組み込み関数があって、
getRotationMatrix で回転の変形行列
getTranslationMatrix で移動の変形行列
を得ることができます。getRotationMatrixの引数は普通の角度でOKです。ラジアンを使う必要もありません。

これらを使って上記スクリプトを書き換えると…

var matA = getTranslationMatrix(-100, -100);
var matB = getRotationMatrix(30);
var matC = getTranslationMatrix(100, 100);
var sel = app.activeDocument.selection;
for (var i = 0; i & lt; sel.length; i++) {
    sel[i].transform(matA, true, true, true, true, 100, Transformation.DOCUMENTORIGIN);
    sel[i].transform(matB, true, true, true, true, 100, Transformation.DOCUMENTORIGIN);
    sel[i].transform(matC, true, true, true, true, 100, Transformation.DOCUMENTORIGIN);
}

うーん、これでは何も改善してませんね。



点(x,y)を表すベクトルをrとして、
(-100,-100)移動の変形行列をA、原点を中心に30°回転の変形行列をB、(+100,+100)移動の変形行列をCとしたとき、

rを(-100,-100)移動した点は
Ar

rを(-100,-100)移動して、原点を中心に30°回転した点は
B(Ar)

rを(-100,-100)移動して、原点を中心に30°回転して、さらに(+100,+100)移動した点は
C(B(Ar))

で表せます。

そして、行列の掛け算はなんと、結合則が使えるのです!
すなわち、

C(B(Ar)) = (CBA)r

これは事前にCとBとAを掛け算した変形行列を求めておけば、変形1回で「(-100,-100)移動して、原点を中心に30°回転して、さらに(+100,+100)移動」したのと同じ状態にできる、ということです。

んで、イラレはその変形行列の掛け算にも関数を用意してくれています。concatenateMatrixというやつです。

var matA = getTranslationMatrix(-100, -100);
var matB = getRotationMatrix(30);
var matC = getTranslationMatrix(100, 100);
var matABC = concatenateMatrix(concatenateMatrix(matA, matB), matC);
var sel = app.activeDocument.selection;
for (var i = 0; i < sel.length; i++) {
    sel[i].transform(matABC, true, true, true, true, 100, Transformation.DOCUMENTORIGIN);
}

なんか上はごちゃごちゃしましたけど、forループがシンプルになったので今度こそできあがりでーす。

ちなみにconcatenateTranslationMatrixとかconcatenateRotationMatrixとか使うともう少し短く書くこともできます。詳しくはOMビューワとかこことか見てください。


おしモアイ

プロフィール

kawamoto_α
(あるふぁ(仮))


InDesignで新聞組版のようなことをしています。

ツイッタ

※ブラウザによっては当ブログからDLしたzipファイルが拡張子なしになることがあるようですが、.zipを補って開いてください。



イラレ用トーンカーブスクリプト(¥1500)



クロソイド式角丸長方形スクリプト(¥500)
Illustrator用
InDesign用



イラレスクリプトをキーボードショートカットで実行するやつ(Win用)