Practice makes Perfect !

ExtendedScript素人です。同じ境遇の方、一緒に脱素人を目指しましょう!

実験008_2022.9-1-2

InDesign2022から「マスターページ」が「親ページ」に変わってしまったからそれに合わせて親ページと言った方がいいのかもしれませんが、まあとにかく馴染まないですね。

前回の記事で指定したマスターが適用されているページを表示するスクリプトについてまとめたのですが、これをドロップダウンリストでやりたかったんです。
p-makes-p.hatenablog.com

自分の知識ではわからなかったので諦めていたのですが、Uske_S (id:uske_S) さんからコメントをいただき、大変貴重な情報を頂くことが出来ました。Uske_Sさんのサイトでも紹介されている「ScriptUIを少しだけ簡単に利用するモジュール」を使わせていただいたのですが、おかげでドロップダウンリストをつくることが出来ました。この度はありがとうございました。
uske-s.hatenablog.com

図で表示しますと、こんな感じです。

今更ですが、恥ずかしながら実はそもそもドキュメントのマスターを読み込み方も分からなかったのです。
出来てしまえばどってことないスクリプトなんですけどね、そこにいたるまでがとても大変でした。こういうことがあるから嫌になってしまう…。ということで作業中のドキュメントのマスターページを読み込むスクリプト

var doc = app.activeDocument;
var myMaster = doc.masterSpreads;
var arr=[];//空の配列を用意
for(var i=0; i<myMaster.length; i++){
	arr.push(myMaster[i].name)
	//配列arrにドキュメントに存在するマスターの名前を格納していく
}

いい加減こういうレベルならすぐに書けるようになるといいのですが。なかなか難しいですね。

実験008_2022.9-1

このマスター…何ページに使われてるの?を解決

InDesign 1ファイルで1,000件以上ある名刺のデータで、更にマスターが10種類とかあったりすると、「あれ、このマスターって何ページで使われてるの?」ってことがよくありまして。それを解決するスクリプトを考えてみました。


下の画面で何番目のマスターが適用されているページを調べたいのかを入力します。


ここでドキュメントのマスターの数より大きい数値を入力すると、「○番目のマスターは存在しません」と表示されます。


番号を入力するとそのマスターが適用されたページをすべて表示してくれます。


適用されているページが1ページもない場合は「指定されたマスターは使用されていません」と表示されます。


かるくおふざけ。

var doc = app.activeDocument;
var mt = Window.prompt("何番目のマスターが適用されているページを探しますか?", "1");
var masNum=(mt-1);
var arr = []; //空の配列を用意
if(mt){ //OKが押されたときのみ実行
	if(mt>app.activeDocument.masterSpreads.length){
		//入力された数字がマスターの数より大きかったとき
		alert(mt+"番目のマスターは存在しません");
		exit();
	}
	for(var i=0; i<doc.pages.length; i++){
		try{
			if(doc.pages[i].appliedMaster ==app.activeDocument.masterSpreads[masNum]){
			// i 番目のマスターが指定したマスターだったとき
			arr.push(i+1); //格納していく
			}
    	}catch (e) {}
	}
if(arr.length==0){
	alert("指定されたマスターは使用されていません");
	}else{
	alert("指定されたマスターは\r"+arr+"\rページで使用されています");
}
}


本当はドロップダウンリストで「ドキュメントのマスターをすべて表示してそこから選ぶ」ってやりたかったのですがわからず断念…。
あとは表示されたページの中で先頭のページにジャンプしますか?イエスで飛びます!みたいにしたいですが、もうちょっと調べてからやってみたいと思います。

AdjustPageItems.jsxとdoScript

AdjustPageItems.jsxは単位をミリでつかえるようにしたい

InDesignのサンプルスクリプトに含まれている「AdjustPageItems.jsx」。複数ページのPDFをInDesignに流し込んだ後で奇数ページと偶数ページに分けてそれぞれ位置をずらすことができるので重宝してます。

ただデフォルトのままだと単位がポイントになっていて入力するたびにmmも一緒に入力しないといけないのが面倒。(自動で換算してくれるのはありがたいが)
そしてたまにスクリプト実行後にドキュメントの単位設定がミリポイントに変わってしまうという現象も。(ちょっと戻ろうかなと思ってUndoした後に起こる現象??)

なので使いやすいようにカスタマイズしました。

①staticLabelを日本語表記に。わたしは垂直方向の移動が+-どっちがどっちか覚えられ人なのでついでに(下+上-)っていれちゃってます。

②オリジナルの65,66行目にあるeditUnits:MeasurementUnits.pointsをeditUnits:MeasurementUnits.millimetersに変更。これで入力単位をミリに設定するのでいちいちmmまで入力しなくて済む。

③しかし入力した数字がなぜかポイントのまま…。5ミリ動かすつもりで5と入力しても5ポイント分(1.8mm弱)しか移動せず。何故。わからず。

そこでオリジナルの90~93行目に注目

var myEvenX = myEvenXField.editValue;
var myEvenY = myEvenYField.editValue;
var myOddX = myOddXField.editValue;
var myOddY = myOddYField.editValue;

④これにそれぞれ0.352778を掛けてミリに変換したけどこんなんでいいのかなとは思う。まあ今のところは問題ないです。

var myEvenX = myEvenXField.editValue*0.352778;
var myEvenY = myEvenYField.editValue*0.352778;
var myOddX = myOddXField.editValue*0.352778;
var myOddY = myOddYField.editValue*0.352778;

doScript

これでまあ満足したんですが、入力する数値を間違えた時にUndoしようと思ってもページ数が多いと戻りたいところまで戻るのが大変!ってなってました。一度のUndoでスクリプト実行前に戻れないものだろうかと思ってました。

そこで検索して出てきたのがdoScript。Uske_SさんのDTPabのサイトを拝見させていただきました。

uske-s.hatenablog.com


ちょっと大変そうだなと思ってたんですが、何の問題もなかったです。ちょうどオリジナルも「function main(){」から始まっているので先頭に次のように入れるだけ。

app.doScript (main, ScriptLanguage.JAVASCRIPT, [], UndoModes.FAST_ENTIRE_SCRIPT);

これでスクリプト実行後に間違いに気づいてもCtrl+Zで瞬時に戻れてしまいます。

サンプルスクリプトはなかなか使えるのがありますのでお時間のある時にいろいろ見たりいじったりするのはおすすめです。

実験007_2022.8-1 未使用レイヤーを削除

使用していないレイヤーがたくさん残っていてうっとうしいと感じるデータってあると思います。また、レイヤーはたくさん作るよりも少ない方が作業がやりやすいと思います。無駄にレイヤーを作成しているデータを見かけることが良くありますが、いざ作業しようとしたときにロックされていたら「あれ?どこのレイヤーだ?」って探さなきゃいけない。そんなときに無駄にレイヤーを作ってしまっていると該当するレイヤーを探すだけでストレスなはずです。

今回は自分の中での課題をクリアできず…

今回は未使用レイヤーを削除するスクリプトをまとめてみたのですが、自分の中での課題をクリアできませんでした。というのは、マスターオブジェクトが存在するレイヤーまで削除されてしまう、これを解決したかったのですが、できませんでした。もちろんオーバーライドされていればレイヤーは残りますが、オーバーライドされていないままだと削除されてしまいます。

先に断りを入れておくというセコい手段に

上記の課題をクリアできなかったので、まずスクリプトで処理を開始する前にアラートで断りを入れております。
画像でいうと「02」の方で「マスターオブジェクトが存在するレイヤーでもオーバーライドされていない場合は削除されてしまいます」と宣言。セコいけど解決できないので仕方ない。
あとはロックされたレイヤーや非表示レイヤーは削除の対象外としています。

実験用にレイヤーを6つ用意。スクリプトを実行すると「から01」「から02」「マスターOBJあり」が削除されます。(オーバライドされていないので)

最後に削除されたレイヤーの数を表示するようにしました。


今回のスクリプトはこんな感じです。
var doc =app.activeDocument;
var layers = doc.layers; 
var count = 0;//削除されたレイヤーの数を最後に表示するために用意
var res = confirm("01_ロックや非表示されたレイヤーは対象外です。\r02_マスターオブジェクトが存在するレイヤーでも\r  オーバーライドされていない場合は削除されてしまいます。\r\r開始しますか?");
if(res==true){
	for( var i = layers.length-1; i >= 0; i--){ 
		if(layers.length==1){
			break;
		}
		if( layers.item(i).allPageItems.length == 0){ 
			if(layers.item(i).locked==true || layers.item(i).visible==false){continue;}//ロックされたレイヤーや非表示レイヤーは削除の対象外としています
				layers.item(i).remove(); 
				count += 1;
		}
	}
	if(count>0){
		alert(count+"個のレイヤーを削除しました");
	}
}


「マスターページにオブジェクトが存在するレイヤーは削除しない」引き続き調査してまいりますー。

実験006_2022.7-2

ガイド引きすぎドキュメントにさよなら ・△・)ノ バイバイ

特に顧客の担当を決めない職場では前回データの修正作業になると前回担当者のクセの残ったデータを扱うことになる。「新規でデータ作成の際は次回他者が扱うことも考えて作るように」と部署内でのルールを作ったはずなのにそんなのお構いなしな人間はどこにだっていますよね。うちには無駄にガイドを引き、無駄にレイヤーを作り(しかもなぜか空のレイヤーも作ってくれちゃう)、無駄にスウォッチ登録する人がいる。当然、その人が作ったデータは触りたくなくなる。見た目が汚いから。

その人のデータを触ることになってしまった時のためのスクリプトを3つ作った。

①ガイドを消去する
②未使用レイヤーを削除する
③未使用スウォッチを削除する

今回はガイドの消去のスクリプトGUIはもうずっとスクリプちんさんのサイトを参考にさせて頂いている。
dtpscriptin.com


無駄にひかれたガイドをドキュメント全体で一気に消去してしまうか作業中のページのみ削除するかを選択できるようにした。ここではswitchを使用。OKボタンとキャンセルボタンで戻り値がOKの時は「1」、キャンセルの時は「2」となるのはとても参考になった。

dtpscriptin.com

var objDlg = new Window("dialog", "削除範囲を指定", [0,0,260,125]);
var objStText01 = objDlg.add("statictext", [20,15,380,40], "削除範囲を指定してください");
var objBtn01= objDlg.add("radiobutton", [20, 50, 120, 80], "ドキュメント");
var objBtn02= objDlg.add("radiobutton", [120, 50, 400, 80], "現在のスプレッド");
objDlg.add("button", [55, 82, 125, 105], "OK", {name:"ok"});
objDlg.add("button", [140, 82, 210, 105], "ESC", {name:"cancel"});

objBtn01.value = true;
objDlg.center();

var rtType = objDlg.show();

switch(rtType){
	case 1: main();
	break;
	case 2 : exit();
	}

function main(){
	if (objBtn01.value == true){
		app.activeDocument.guides.everyItem().remove();
		}
	else{
		app.activeWindow.activeSpread.guides.everyItem().remove();
		}
	}

それにしてもみんなで決めたルールもしくは上司が決めたことを守らないで、自分のやり方がいちばんと思うのって、そりゃ誰からも相手にされなくなりますよね

実験005_2022.7-1

名刺データの管理

ある顧客の名刺データが2,500件以上ある。前任者はこれを店舗ごとに管理したものだからInDesignのファイル数が70近くなっており、注文が来ると

①店舗名で付けたファイル名から使用するInDesignファイルを探す(この時点で無駄)
②該当ファイルを開いて受注した名刺を1件ずつ「氏名」で検索し、該当ページをメモ
③メモをもとにページ指定し、PDFを書き出し面付、印刷

という手法を取っていた。顧客が異動の時期になれば注文件数も増大し深夜残業になるのは当然である。しかもQuarkを扱ってた方なので、InDesignへの移行もだいぶ遅れた。あるとき名刺のデザインが一新されるということで、もう自分にはできないと言い出したのでだったらやらせてくれと手をあげた。

新フォーマットでのデータ作成は以下のとおり。
①名刺に載せる情報はすべてExcelで支給してもらう
②データ結合で展開
③細かい調整(全角半角統一など)は検索置換のクエリを登録しておいてスクリプトで呼び出し一括調整
店舗ごとにInDesignファイルを作るのではなく、1ファイルで管理した。

では受注した際はどうしているかというと、次のように処理している。
①注文のリストはExcelで来るので氏名の行をコピーしメモ帳に貼り付けテキストデータで保存
②上記テキストデータをリストとして、スクリプトで1行ずつ読み込み、1行ずつ繰り返しInDesignファイルの最終ページに移動させる。
これで下版の際にPDFを書き出す際のページ指定も「最終ページ番号-受注件数+1」に「-」をつければいいだけなので簡単になる。

上記作業で「リストを検索してヒットしたページを最終ページに移動するというスクリプト」は以下のとおり。

var doc = app.activeDocument;
//検索オプションGrep
app.changeGrepPreferences = NothingEnum.nothing;
app.findGrepPreferences = NothingEnum.nothing;
app.findChangeGrepOptions.includeHiddenLayers = false;//非表示レイヤーを含めるかどうか
app.findChangeGrepOptions.includeMasterPages = false;//マスターページを含めるかどうか
app.findChangeGrepOptions.includeFootnotes = false;//脚注を含めるかどうか


function mvPg(x){
app.findGrepPreferences.findWhat=x;
var gr=doc.findGrep(); // 検索だけ
var grl=gr.length; 

for (i=grl-1; i>=0; i--) { 
    try{
	pageNum=(gr[i].parentTextFrames[0].parentPage.name-1);
    doc.pages[pageNum].move(LocationOptions.AT_END,doc.pages[-1]);//検索したページをdoc2の最後に複製
    }catch (e) {}
}
};

filename = File.openDialog("リストのテキストファイルを選択してください。");
if (filename)
{
fileObj = new File(filename);
var lineArr = new Array();
fileObj.open("r"); // 読み込みモード

while(!fileObj.eof) {
	var idNum= fileObj.readln();
mvPg(idNum);
}
fileObj.close();
}
app.changeGrepPreferences = NothingEnum.nothing;
app.findGrepPreferences = NothingEnum.nothing;

alert("移動しました");

mottainaiDTPさんのサイトを参考にさせて頂いている。
mottainaidtp.seesaa.net

しかしInDesignファイルでページ数が2,500ページくらいになるとスクリプトをしようしても検索&移動にだいぶ時間がかかる。上記スクリプトにはプログレスバーを使用していないが今使っているものはプログレスバーも組み込んだ。(このプログレスバーを組み込むのがわけがわからず大変だった)
今後の課題はこの辺の時間の短縮と考えている

実験004_2022.6-1

背幅を入力して表紙(貼込)用のドキュメントを作成するスクリプト

入稿された表紙のデータが見開きになっていない場合、InDesignに貼って見開きのPDFを作成することがあります。また見開き(背幅込)で入稿されたAIデータでも勤務先ではAIから直接PDF作成せずに、一度InDesignに貼りこんでからPDF作成という流れで統一しています。

ページものの表紙はページ数によって背幅が変わるので、テンプレートの準備はあまり意味がありません。これをスクリプトで解決できないか、ということで考えてみました。
主に仕上がりサイズはB5またはA4のページものが多数だと思いますのでそれ以外のサイズは想定していません。

やってみたいこと

背幅を入力するだけでB4長辺・A3長辺に背幅を足したドキュメントを作成する

下のような画面を用意し、仕上がりサイズと背幅の設定、貼込用のグラフィックフレームを全面塗り足しありで作成するか、表1~表4個別・塗り足しなしで作成するかを設定します。

この画面の作成はリプちんさんのスクリプちんを参考にさせていただきました。
dtpscriptin.com

「全面」にチェックをいれて実行すると結果的に図のようなドキュメントが作成されます。

※グラフィックフレームをドキュメントサイズよりも天地左右5mmずつ大きくしているのは貼り込んだAIやPDFトンボの位置がずれてないかわかりやすくするためです。

「個別」にチェックをいれて実行すると結果的に図のようなドキュメントが作成されます。

背幅が分かるように折りトンボを追加・仕上がりが分かるように罫線も追加

「折りトンボ」というレイヤーと「わく」というレイヤーを作成して、それぞれ0.1mmのスミ罫を描画します。校正提出時にお客さんに分かりやすいようにしておきます。もちろんカッター等で仕上げて提出する場合などは不要ですが…

こんな感じで作りました

背幅を入力しないと入力を促すアラートが出ます。背幅が0でいいときは0を入力します。

//背幅の入力画面
var uDlg   = new Window("dialog","表紙サイズ設定",[0,0,190,175]);
var sText  = uDlg.add("statictext",[25,10,150,25], "仕上がりサイズを選択");
var cb01   = uDlg.add("radiobutton", [25, 30, 75, 60], "B5");
var cb02   = uDlg.add("radiobutton", [100, 30, 150, 60], "A4");
var sText  = uDlg.add("statictext",[25,58,100,75], "背幅を入力");
var sehaba = uDlg.add("edittext",[95,54,125,80]);
var sText  = uDlg.add("statictext",[130,58,180,75], "mm");
var sText  = uDlg.add("statictext",[25,90,150,105], "フレームサイズを選択");
var cb03   = uDlg.add("radiobutton", [25, 110, 75, 140], "全面");
var cb04   = uDlg.add("radiobutton", [100, 110, 150, 140], "個別");
var okBtn  = uDlg.add("button",[45,140,45+100,140+20], "OK");

sehaba.active = true;
cb01.value    = true;
cb03.value    = true;
uDlg.center();
var rtType = uDlg.show();
var sehabaX = sehaba.text;//入力された数値

//処理の実行
if((sehaba.text=="")&& (rtType==1)){
	//背幅を入力しないままOKを押すとアラート
	alert("数値を入力してください");
}else{
	//OKボタンを押すと処理開始
	if(rtType==1){
		DocAdd();
	//閉じるボタンを押すと終了
	}else (rtType==2){
		exit();
	}
}

//メイン処理
function DocAdd(){
	doc = app.documents.add();
	var dp = doc.documentPreferences;
	var sumB5 = 364+Number(sehabaX)+"mm";
	var sumA4 = 420+Number(sehabaX)+"mm";
	var tanpen;
	
	if(cb01.value) {
		dp.pageWidth = sumB5;
		dp.pageHeight = "257mm";
		tanpen =182;
	}else{
		dp.pageWidth = sumA4;
		dp.pageHeight = "297mm";
		tanpen =210;
	}

	//マスターページのマージン・段組設定
	docSet();

	//グラフィックフレームを作成
	var lay1 = doc.layers[0];
	var rct1 =msp.rectangles.add();
	if(cb03.value) {
		//全面:塗り足しありで作成
		rct1.contentType = ContentType.GRAPHIC_TYPE;
		rct1.geometricBounds=[msp.bounds[0] - 5, msp.bounds[1] - 5, msp.bounds[2] + 5, msp.bounds[3] + 5];
	}else{
		//H1~H4個別:塗り足しなしで作成
		rct1.contentType = ContentType.GRAPHIC_TYPE;
		rct1.geometricBounds=[msp.bounds[0], msp.bounds[1], msp.bounds[2], msp.bounds[3]/2-(sehabaX/2)];
		var rct2 =msp.rectangles.add();
		rct2.contentType = ContentType.GRAPHIC_TYPE;
		rct2.geometricBounds=[msp.bounds[0], msp.bounds[1]+tanpen+Number(sehabaX), msp.bounds[2], msp.bounds[3]];
	}

	//折りトンボの追加
	var lay_se = doc.layers.add({name:"折りトンボ"});
	var gl1 = msp.graphicLines.add();
	gl1.geometricBounds=["-3mm", tanpen, "-2mm", tanpen];
	gl1.strokeColor = doc.swatches.itemByName("Registration");
	gl1.strokeWeight = "0.1mm";
	var gl2 = gl1.duplicate(undefined, [0, Number(dp.pageHeight)+5]);
	var ST = msp.groups.add([gl1, gl2]);
	ST.duplicate(undefined, [sehabaX, 0]);
	lay_se.locked = true;

	//仕上がり罫を作成
	siagariK();
}

function docSet(){
	msp = doc.masterSpreads[0].pages[0];
	mg =msp.marginPreferences;
	mg.columnCount = 2;
	mg.columnDirection = HorizontalOrVertical.HORIZONTAL;
	mg.columnGutter = sehabaX;
}

function siagariK(){
	var lay_waku = doc.layers.add({name: "わく"});
	var imgObj = msp.rectangles.add();
	with(imgObj){
		contentType = ContentType.GRAPHIC_TYPE;
		geometricBounds =msp.bounds;
		strokeWeight = "0.1mm";
		strokeColor = "Black"
		fillColor = "None"
	}
	lay_waku.locked = true;
	lay_waku.visible = false;
	//一番下のレイヤーをアクティブに
	doc.activeLayer= doc.layers.lastItem();
}