はじめに
こんにちは。初心者エンジニア2年目です。エンジニアといいつつ業務で開発をした経験はほぼなく、JavaScriptをまともに触るのは今回が初めてです。至らぬ点もあるかと存じますが温かく見守っていただけると幸いです。
さて、今回私に与えられた課題は名刺の大量生産です。社員数分の名刺をIllustratorで作成するのですが、「同じフォーマットで文字だけ差し替えればいいじゃん」と思いきや、記載する肩書の数や保有資格の数、文字列の長さの違いからフォントサイズ・配置を微調整する必要がありました。当記事では、それらの微調整含め名刺のPDFデータ作成までの工程を完全自動化する道のりをまとめます。
目次
ExtendScriptとは
下準備①:ExtendScript Debuggerの導入
下準備②:Illustratorで.jsxファイルを実行する方法の確認
実装⓪:今回自動化する工程の確認
実装①:CSVファイルのデータを流し込む
実装②:文字サイズ・位置の自動調整
---調整①:指定の縦横幅に収まる文字サイズへ変更
---調整②:座標による位置調整
---調整③:グループ化して全体の位置調整
実装③:アイコン(画像ファイル)を配置
実装④:アウトライン化
実装⑤:PDF化
最後に
ExtendScriptとは
ExtendScriptは、Adobe製品(illustrator / Photoshop / InDesign 等)を自動化するためのスクリプトです。基本的にはJavaScriptと同じような文法で、編集作業や書出しなどの反復作業を自動でおこなうことができます。
下準備①:ExtendScript Debuggerの導入
開発に際し、デバッグ環境を整えることから始めました。使用したのはVisual Studio CodeのExtendScript Debuggerという拡張機能。
AdobeのExtendScript Toolkit(ESTK)は開発が終了しているため、このExtendScript Debuggerを用いた開発が現状多いようです。
Visual Studio Codeの拡張機能のタブから以下画像のプラグインを検索してインストールします。

下準備②:Illustratorで.JSXファイルを実行する方法の確認
Illustrator側から.JSXファイル(ExtendScriptのファイル)を実行するには、Illustratorファイルを開いて
ファイル > スクリプト > その他のスクリプト > (任意のJSXファイル)
の順で選択します。
Visual Studio Codeから実行するときは、Illustratorを立ち上げた状態でVisual Studio Codeで実行したい.jsxファイルを開き、
**実行とデバッグ ⇒ ExtendScript ⇒ Attach ⇒ Illustrator(※該当のバージョン) ⇒ (画面下方)Eval in Adobe...**の順にクリックします。
実装⓪:今回自動化する工程の確認
それでは実装に入りますが、まずはこの記事でどんな処理を実装していくか整理しておきます。
準備したもの
- 各要素を配置したテンプレートファイル(.ai)
- 名刺記載事項が入力された名簿(.csv)
- 資格等のアイコン画像データ(.png)
実装した処理の流れ
- 名簿(CSVファイル)を開く
- 名簿内の一人一人のレコードに対し以下を実施(ループ処理)
① テンプレートに名簿(CSV)のデータを流し込む
② 文字サイズ・位置の調整
③ アイコン(画像ファイル)を配置
④ アウトライン化して別名保存
⑤ PDF化して別名保存
実装①:CSVファイルのデータを流し込む
テンプレートのイラレファイルにはサンプルの文字列をデザインに沿って配置しました。テキスト部分は折り返しが発生するエリア内文字ではなくポイントテキストにしました。
早速データ流し込みに取り掛かりましょう。今回は以下のようなコードで実装しました。(一部抜粋)
var csvFile = File("パス・ファイル名.csv");
csvFile.open("r");
var lines = csvFile.read().split("\n");
csvFile.close();
// ==== CSVを1行ずつ処理 ====
// 1行目はヘッダなので i=1 から
for (var i = 1; i < lines.length; i++) {
var cols = lines[i].split(",");
var fullname = cols[1];
var phone = cols[2];
var email = cols[3];
// ==== CSVの内容をテンプレに流し込む ====
var doc = app.open(new File("パス・ファイル名"));
doc.textFrames[0].contents = fullname;
doc.textFrames[5].contents = phone;
doc.textFrames[6].contents = email;
//後続処理
}
この例では、どのテキストを操作するかを doc.textFrames のインデックス([0], [1] …)で指定しています。テキストの内容はcontentsプロパティで変更できます。
実装②:文字サイズ・位置の自動調整
個人的に一番苦戦したのが文字サイズ・位置の微調整です。名刺の情報量(役職有無・資格の数 等) には個人差があり、同じレイアウトでも文字がはみ出したり、文字同士がかぶったりしてしまうためです。実装では後述の3種類の調整(文字サイズ・位置・グループでの調整)を組み合わせました。
調整①:指定の縦横幅に収まる文字サイズへ変更
今回は一定の幅・高さを超えると文字サイズが小さくなるように実装しました。要素の各頂点座標から幅・高さを算出し、基準値と比較します。基準値を超える場合は、while文 で幅が基準以下になるまで文字サイズを段階的に縮小します。読める文字サイズを保つため、フォントサイズが 5pt に到達した時点で break します。
各頂点の座標を取得する際はobj.geometricBoundsプロパティを使います。配列[左,上,右,下] の形で座標が返ってきます。文字サイズはobj.textRange.characterAttributes.sizeプロパティで指定できます。以下は高さ調節のサンプルコードです。
function getHeight(frame) {
var b = frame.geometricBounds;
return Math.abs(b[1] - b[3]);//「上ー下」=高さ
}
function autoFitCommon(target){
// 現在の文字サイズ
var size = target.textRange.characterAttributes.size;
// 高さが8mm以上のときは8mm以下になるまで文字サイズを0.5ずつ下げる.
var LIMIT_HEIGHT_PT = 8 * 2.834645669;//mmをptに変換
var height = getHeight(target);
while (height > LIMIT_HEIGHT_PT) {
size -= 0.5;
if (size < 5) break;
target.textRange.characterAttributes.size = size;//文字サイズの調整
target.textRange.characterAttributes.leading = size + 0.5;//行間の調整
app.redraw();
height = getHeight(target);
}
}
autoFitCommon(doc.layers[0].textFrames[0]);
調整②:座標による位置調整
テキストオブジェクトは、文字数が多いと名刺の外にはみ出したり、行数が増えると他の要素と重なったりしがちです。そこで今回は、基準となる座標同士を比較して「はみ出し」や「被り」を検知し、必要に応じて位置を自動調整する方針にしました。
位置指定にはobj.positionを使います。obj.positionは[x, y]の配列で、要素の左上の座標を指定できます。次のように設定します。
obj.position = [x, y]
長くなるため、座標同士の比較や位置の微調整の詳細は割愛します。
調整③:グループ化して全体の位置調整
レイアウト調整を行う際、複数のオブジェクトを まとめて移動・配置したい場面はよくあります。例えば、今回のケースでは、名前、肩書、保有資格…といった複数のテキストフレームを、相対位置を保ったまま移動したいことがあります。
ここでは、テキストフレームを一時的にグループ化し、まとめて移動したあとにグループ解除する方法を紹介します。
まずグループ化は以下のように配列にまとめたテキストフレームを新規グループに順に移動させます。グループへの移動はobj.moveメソッドを使います。
function adjustLayout(doc) {
//3つのテキストフレームをグループ化する
var itemsToGroup = [];
for (var i = 0; i <= 2; i++) {
itemsToGroup.push(doc.layers[0].textFrames[i]);
}
//新規グループを作成し、テキストフレームを順に移動させる
var group = doc.layers[0].groupItems.add();
for (var j = 0; j < itemsToGroup.length; j++) {
itemsToGroup[j].move(group, ElementPlacement.PLACEATEND);
}
グループ化後の位置調整は先ほどと同様にobj.positionで行います。
//グループの位置を指定する
group.position = [x, y];
グループ解除の際は先ほどのグループ化とは逆でグループから順に要素を取り出し、空になったらグループを削除します。
//グループ解除
while (group.textFrames.length > 0) {
group.textFrames[0].move(group, ElementPlacement.PLACEBEFORE);
}
group.remove();
}
実装③:アイコン(画像ファイル)を配置
資格情報を載せる際、資格のアイコンを配置したいですよね。画像ファイルを配置するときには、Fileオブジェクトを用意し、ドキュメントに新規PlacedItemを追加して、PlacedItemのfileプロパティに先ほどのFileを割り当てます。これで指定した画像がドキュメントに配置されます。
var iconFile = new File("パス・ファイル名");
var placed = doc.placedItems.add();
placed.file = iconFile;
画像の縮尺を変えたいときには
placed.resize(scale, scale);
のように書きます。scaleには100を等倍として任意の拡大率を入力します。
実装④:アウトライン化
ここでは対象レイヤーのテキストオブジェクト(textFrames)を順にアウトライン化します。アウトライン化するときはcreateOutlineメソッドを使います。以下のコードで実行できます。
doc.textFrames[i].createOutline();
また、ループ処理に少し工夫が必要です。テキストオブジェクトはインデックスで指定しますが、テキストをアウトライン化するとtextFrames から除外されるため、配列のインデックスが都度繰り上がります。そのため、インデックスを増やしながら処理するのではなく、常にtextFrames[0]をアウトライン化し、textFrames.lengthが 0 になるまでループすることで、全テキストを安全に処理することができます。
function outlineAll(doc) {
var textLength = doc.layers[0].textFrames.length
for (var i = 0; i < textLength; i++) {
var tf = doc.layers[0].textFrames[0];
tf.createOutline();
}
}
実装⑤:PDF化
印刷物を制作するときにはPDF化までがセットですよね。PDF化したいときはPDFSaveOptionsオブジェクトを作成します。以下のコードでファイルをPDFとして保存できます。
var pdfFile = new File("任意のパス/ファイル名.pdf");
var pdfOptions = new PDFSaveOptions();
doc.saveAs(pdfFile, pdfOptions);
最後に
こうして大人数の名刺をまとめて生成できるようになりました!
本記事では、CSVの名簿からIllustratorテンプレートへ差し込み、文字サイズ・位置の自動調整、アイコン配置、アウトライン化、PDF書き出しまでを一連で自動化する方法をまとめました。
名刺は情報量の個人差が大きく、一人一人の微調整に労力がかかることから負担の大きい作業だと思いますが、調整ロジックを組み合わせることで人手のいらないテンプレ運用を実現できます。
ぜひ皆さんもIllustratorの自動化を試してみてはいかがでしょうか?