Practice makes Perfect !

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

データ結合で発生するコロン(:)みたいな制御文字を消したい

毎日暑いですね。ブログって書かなくなると面倒になるものですね。立ち上げ当初はブログで稼いでやるぜみたいなことちょっとだけ思ったりしてましたけど笑。このまま何も書かなくなりそうと危惧したので2ヶ月前のTwitter(X)でのやり取りを載せておきたいと思います。

データ結合で発生する制御文字(:)を消したい!!

こんなことをPostしてみたら、ありがたいことにリプをいただいて解決することが出来ました。ご回答いただいた皆様、その節は大変お世話になりました。

データ結合はよく使うけど、制御文字を表示すると出てくるコロンみたいなマークが邪魔で仕方なかったのです。

この邪魔なマークを削除する手順を載せておきます。

①テキスト検索で検索文字列に図のように入力
正規表現では拾えません
置換文字列は空に

②残念ながら①だけでは消えませんでした。それで構造から削除できるというコメントをいただいたので試してみると消せました。
※図のようなアラートがでるので「解除」をクリック

これだけで解決しました。

実はTwitter(X)で投げかけるのはドキドキだったのですが思い切ってPostしてみてよかったです。
ちなみに選択したテキストフレームからのみ、削除したいという場合はタグのフレームから解除をクリックすると消えます。

上記①・②の作業もスクリプトを使えば一発でした。
やっぱりスクリプトって素晴らしい!

app.activeDocument.xmlElements[0].xmlElements.everyItem().untag();

こうやってまとめてみてはいますが、はっきり言って構造とかタグ要素とかXMLとかちゃんと理解してないです
奥が深いなInDesign…( ;∀;)

実験010_2023.4-1

見開きPDFをInDesignを使って単ページにバラすスクリプト

ページ物が見開き(PDF)で入稿された場合の対応

ページもののデータが見開きのPDFで入稿されることがたまにあります。しかし見開きで入稿されてしまうと、中綴じにしろ無線綴じにしろ、面付けできません。勤務先では面付作業は面付ソフトを使いますが、その際は単ページのPDFを使って面付していきます。

面付について簡単に説明すると、例えばA4, 8ページ, 中綴じ, 左開きという仕様で、左右返しで印刷する場合であれば図のような面付になります。

菊判半裁というサイズにはA4が4ページ(両面で8ページ)面付できます。
8ページ・中綴じの面付なのでおもて面は、見開きPDFが使えるのではと思われるかもしれませんが、ページ数が変われば面付も当然変わってきます。うら面の図がわかりやすいと思いますが、見開きのPDFデータとは全然違う面付になります。

なので見開きのPDFで入稿されてしまった場合は「単ページのPDFで再入稿してください」とお願いしているのですが、不思議なことにまれに「単ページで書き出せませんので、なんとか対応できませんか」とか、「それは御社の仕事でしょう」となんとも高飛車なお返事をいただくことがあります。

見積の料金的にそれってどうなんですか、って営業に言っても、作業が進まないから対応してあげて、なんていわれることも多く、仕方なくため息をつきながら対応してます。

では実際どうバラしていくのか。

大まかにいうと、①見開きPDFをInDesignスクリプトで貼っていき、②ドキュメントサイズを仕上がりサイズに変更、③単ページでPDFを書き出すといった流れになります。
※今回のスクリプトは貼り込んだPDF以外のオブジェクトが存在することは想定していません。

1)見開きPDFをInDesignスクリプトで自動貼込

自動でPDFを貼り込んでいくスクリプトは色々あると思うのですが、わたしは「MultiPageImporter」が使い慣れてしまいました。
creativepro.com

仕上がりサイズがA4のものなら見開きのサイズはA3になるので、A3のドキュメントに自動で貼り込みます。


2)各ページの後に空白ページを挿入

後でドキュメントの幅のサイズを半分(見開き)にすることを考慮して各ページの後に空白ページを挿入します。見開きのものを分割するのでページ数は倍にならなければいけません。そのために空白ページを挿入しておくということです。

var doc = app.activeDocument;
var pgObj= doc.pages;
var pgNum1 = pgObj.length;

//1ページ毎に空白ページを挿入
for (var i = 0; i<pgNum1*2; i++){
	var addPage = pgObj[i];
	pgObj.add(LocationOptions.AFTER, addPage);
	i = i+1;
	}

この処理でInDesignのページは図のようになります。

3)ドキュメントの幅を半分に設定
with (doc.documentPreferences){
pageWidth = pageWidth/2;
facingPages = true; //見開き
pageBinding = PageBindingOptions.LEFT_TO_RIGHT; //左開き対応
allowPageShuffle = true; //ドキュメントページの移動を許可
}


4)貼り込んだPDFを正しい位置に移動

ドキュメントの幅が半分に、さらに見開きになって、貼り込んだPDFの位置がちょうどページ幅の半分の位置にくるので、これらを正しい位置に移動させます。

var w = doc.documentPreferences.pageWidth;
var pgNum2 = pgObj.length; //先の処理でドキュメントのページ数が変わったのでpgNum2とする

for (var j = 0; j<pgNum2-1; j++){
	var obj = pgObj[j].pageItems[0];
	obj.move(undefined, [w/-2, 0]); //ページ幅の半分移動
	j = j+1;
	}
5)先頭ページに配置されているPDFを最終ページに複製

先頭ページに配置されている見開きPDFの最終ページにあたる部分(説明が下手ですみません)をコピーしてInDesignドキュメントの最終ページの元の位置にペーストする。

//貼り込んだPDFの最終ページをInDesignドキュメントの最終ページに複製
var win = app.activeWindow;
pgObj[0].pageItems[0].select();
app.copy();
var act = app.menuActions.itemByName("元の位置にペースト");
win.activePage = pgObj[-1];
act.invoke();


6)あとはInDesignから単ページでPDFを書き出して終了です。

ちなみにA3の2つ折り(A4×4ページ)でしたら見開きのまま入稿していただいても問題ありません。というか、そのまま入稿していただいた方がA3を2面というかたちで面付できるので作業が楽になります。

今回のスクリプトは次のようになります。
app.doScript (main, ScriptLanguage.JAVASCRIPT, [], UndoModes.FAST_ENTIRE_SCRIPT);

function main(){
var doc = app.activeDocument;
var pgObj= doc.pages;
var pgNum1 = pgObj.length;

//1ページ毎に空白ページを挿入
for (var i = 0; i<pgNum1*2; i++){
	var addPage = pgObj[i];
	pgObj.add(LocationOptions.AFTER, addPage);
	i = i+1;
	}

//ドキュメントを半分のサイズの見開きに設定
with (doc.documentPreferences){
pageWidth = pageWidth/2;
facingPages = true; //見開き
pageBinding = PageBindingOptions.LEFT_TO_RIGHT; //左開き対応
allowPageShuffle = true; //ドキュメントページの移動を許可
}

//貼りこんだPDFを正しい位置に移動
var w = doc.documentPreferences.pageWidth;
var pgNum2 = pgObj.length; //先の処理でドキュメントのページ数が変わったのでpgNum2とする

for (var j = 0; j<pgNum2-1; j++){
	var obj = pgObj[j].pageItems[0];
	obj.move(undefined, [w/-2, 0]); 
	j = j+1;
	}

//貼り込んだPDFの最終ページをInDesignドキュメントの最終ページに複製
var win = app.activeWindow;
pgObj[0].pageItems[0].select();
app.copy();
var act = app.menuActions.itemByName("元の位置にペースト");
win.activePage = pgObj[-1];
act.invoke();

}


【課題】
pages と spreadsを間違えると動きが変わってしまい、ちゃんと把握できていないと実感(涙)

実験009_2022.10-1-2

1行に収まっていない段落があるテキストフレームを探し出し、該当する段落を1行に収める

前回は該当するテキストフレームを探し出して黄色で塗りつぶすというところまでまとめました。
今回はその該当テキストフレームの中を覗いていくスクリプトです。

前回のスクリプトはこちら。

var doc = app.activeDocument;
var PG = doc.pages;
for(var i=0; i<PG.length; i++){ //ドキュメント全体で処理
	var TF = PG[i].textFrames;
	for(var j=0; j<TF.length; j++){ //全てのテキストフレームを対象に
		if(TF[j].paragraphs.length !=TF[j].lines.length){
		//対象のテキストフレームの段落数が行数と一致しない時
		// =1行で収まっていない という考え
		TF[j].fillColor="Yellow";
		}
	}
}

上記の

TF[j].fillColor="Yellow";

の部分を変えていきます。
該当するテキストフレームの中で「1段落の長さが1行でないときその段落を選択する」というスクリプトは次の通り。

var HIT = TF[j]; //該当するテキストフレームをHITという変数に代入
var HIT_P = HIT.paragraphs;
for(var k= 0; k<HIT_P.length; k++){
	if(HIT_P[k].lines.length !=1){
	//HIT(テキストフレーム)の中で1段落の長さが1行でないとき
	//その段落を選択する
		HIT_P[k].select();
	}
}


そうすると図のように、該当する段落が選択された状態になります。

あとはこれを長体をかけてくれて1行に収めてくれるスクリプトを書けば、ドキュメント全体で自動で処理してくれます。

まとめのスクリプトはこんな感じです。

var doc = app.activeDocument;
var PG = doc.pages;
for(var i=0; i<PG.length; i++){ //ドキュメント全体で処理
var TF = PG[i].textFrames;
	for(var j=0; j<TF.length; j++){ //全てのテキストフレームを対象に
	if(TF[j].paragraphs.length !=TF[j].lines.length){
		//対象のテキストフレームの段落数が行数と一致しない時
		// =1行で収まっていない という考え
	var HIT = TF[j]; //該当するテキストフレームをHITという変数に代入
	var HIT_P = HIT.paragraphs;
		for(var k= 0; k<HIT_P.length; k++){
		if(HIT_P[k].lines.length !=1){
		//HIT(テキストフレーム)の中で1段落の長さが1行でないとき
		//その段落を選択する
		HIT_P[k].select();
				
		//ここに「選択テキストに長体をかけて1行で収めるスクリプト」を
		//書きます
						
		}
		}
	}
	}
}

「選択テキストに長体をかけて1行で収めるスクリプト」については前回リンク貼っておきましたがここにも貼っておきます。
seuzo.net
sysys.blog.shinobi.jp
せうぞー (id:seuzo) さん、kawamoto_α(あるふぁ(仮)) さん、ありがとうございます。

ちなみに今回紹介したわたしの書いたスクリプト、オーバーセットテキストには非対応でした(´;ω;`)

あとこちらに自分でもまとめてました。
p-makes-p.hatenablog.com

実験009_2022.10-1

1行に収まっていない段落があるテキストフレームを探し出したい

昨日Twitterで呟いてみたんですけど、1行に納まっていない段落があるテキストフレームをドキュメント全体から探し出したいと思っていました。

どういうことかというと図のような感じです。

このように1段落1行で収まっていないテキストフレームを探し出したいのです。

名刺のお仕事が数千件入るというのですが、データ結合で展開した後の処理として、たとえばE-mailが長くて2行に跨いでしまうということがあると思います。そういうのを自動で1行に収めるというのをやりたいのです。

複数行に跨ぐ行を長体をかけて1行に収めるスクリプトについてはネットで検索すると出てくるので、今回は上記のように該当するテキストフレームを探し出すところまでをやってみます。
seuzo.net
sysys.blog.shinobi.jp


まず、考え方として「1段落1行で収まっていない」ということを「段落数と行数が一致していない」というように考えました。

paragraphs.length != lines.length
//段落数と行数の不一致


あとは特に問題ありませんでした。試しに作業中のドキュメントの1ページ目にあるテキストフレームで該当するものを黄色く塗りつぶすという処理は次の通り。

var doc = app.activeDocument;
var PG = doc.pages[0];
var TF = PG.textFrames;
for(var i=0; i<TF.length; i++){ //全てのテキストフレームを対象に
	if(TF[i].paragraphs.length !=TF[i].lines.length){
	//対象のテキストフレームの段落数が行数と一致しない時
	// =1行で収まっていない という考え
	TF[i].fillColor="Yellow";
	}
}

ドキュメント全体で処理するために次のようにしました。

var doc = app.activeDocument;
var PG = doc.pages;
for(var i=0; i<PG.length; i++){ //ドキュメント全体で処理
	var TF = PG[i].textFrames;
	for(var j=0; j<TF.length; j++){ //全てのテキストフレームを対象に
		if(TF[j].paragraphs.length !=TF[j].lines.length){
		//対象のテキストフレームの段落数が行数と一致しない時
		// =1行で収まっていない という考え
		TF[j].fillColor="Yellow";
		}
	}
}

次回は該当テキストフレームの該当段落に対して処理を行るスクリプトについてまとめます。

for...in文

前回連想配列についてまとめたので、次にfor...in文をまとめてみます。
for...in文は①オブジェクトのプロパティや②プロパティの値を効率よく抽出できます。
for文と何が違うのかと思ったんですが、初期化やループ条件の記述をしなくてよいというところでしょうか。

まず次のようなオブジェクトを例にあげます。

var obj = {apple:"りんご", orange:"みかん", banana:"バナナ"};

これでapple, orange, bananaの情報が入ったオブジェクト(obj)ができました。
これらの各プロパティに対して処理を実行する時に使うのがfor...in文です。

次のような構文になります。

for( var 変数 in オブジェクト ) { 処理 }

上記の例で次のように書くと、プロパティをすべて出力することができます。

var obj = {apple:"りんご", orange:"みかん", banana:"バナナ"};
for(var key in obj){
	$.writeln(key);
	}

実行結果は画像の通り。

次に値を取得してみます。

値を取得する場合は「オブジェクト[ プロパティ ]」のように書きます。

var obj = {apple:"りんご", orange:"みかん", banana:"バナナ"};
for(var key in obj){
	$.writeln(obj[key]);
	}

実行結果は画像の通り。先ほどとは違いますね。


ちなみにfor...in文は配列にも利用できるそうです。

var obj = ["apple", "orange", "banana"];
for(var key in obj){
	$.writeln(obj[key]);
	}

ただし要素の順番通りに出力されることが保証されているわけではないようです…。順番通りに出力したい時は素直にfor文を使う方がよいそうです。

まとめてみれば簡単な感じなんですけど…どう使うか、わたしに使いこなせるか…自信がありません…

for...in文をラーニング…の前に連想配列をラーニング

まだまだ分からないことだらけですね。以前からfor...in文というのは何だろうと気になっていたのでいろいろと調べていました。

for( var 変数 in オブジェクト ) { 処理 }

こういうやつです。ところがこれについて調べていくうちに連想配列について学ばなくちゃいけないのかなと思い始めたので、今回はそれについてまとめます。

そもそもJavaScriptには「連想配列」という言葉は存在しないとか出てきていきなり躓いてます…?

連想配列は、配列の添字(index)に好きな名前をつけることができる配列とのこと。
普通の配列では、

var a = [100, 200, 300];
alert (a[0]);
//100と表示される

つまり

var 変数名 = ["値a", "値b", "値c"];

といった感じで宣言して添字に数字が割り振られていた。

それが連想配列では、

var a = {apple:100, orange:200, banana:300};
alert (a["apple"]);
//100と表示される

つまり

var 変数名 = {キーa:"値a", キーb:"値b", キーc:"値c"};

こんな感じで宣言して添字に好きなように名前がつけられる。

var a = {apple:100, orange:200, banana:300};
alert (a.apple);

としても結果は同じ。

連想配列に要素を追加する場合は下の例だと

var a = {apple:100, orange:200, banana:300};
a.peach = 400;

とするだけ。もしくは

a["peach"] = 400;

とりあえず連想配列については何となく理解できた。
次はこれをfor...in文でループさせる方法をまとめる予定。

実験008_2022.9-1-3

「このマスター…何ページに使われてるの?を解決」というタイトルで今月の初めにまとめていましたが、その後、Uske_S (id: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にドキュメントに存在するマスターの名前を格納していく
}

②ドロップダウンリストでマスターページ名を表示し選択できるようにする

ScriptUIについては上にリンクを貼ってますのでそちらよりご確認ください。

③指定したマスターが適用されているページを配列に格納

function myFunc(){
	var arr2 = []; //空の配列を用意
	var masName = mySUI[1].selection.text;
	/*mySUI[1]は使わせていただいたモジュールのコントロールタイプのうち
	2番目にドロップダウンリストを使用しているので、
	それの選択した内容にアクセスするためのものです*/
	var count=0 
	//最終的に指定したマスターが適用されているページの総数も表示する
	for(var j=0; j<doc.pages.length; j++){
	try{
		if(doc.pages[j].appliedMaster.name ==masName){
		//jページのマスターが指定したマスターだったとき		
		arr2.push(j+1); //格納していく
		count++;
		}
    	}catch (e) {}
}

④適用されているページとそれが全部で何ページなのかをアラートで表示する

結果として以下のように表示されます。

自分で作ったスクリプトを仕事で実用できることほどうれしいことはないですね。今後もこれスクリプトでできないかな?みたいなのを思いついたらどんどん作っていきたいと思います。