CoffeeScriptはAdobeCSスクリプトのエクリチュールとなりえるか
まえまえから気になっていたのでInDesignをうごかすJavaScriptをCoffeeScriptでかくとどんなかんじになるかためしてみた.
あくまでためしてみるだけだしInDesignでやるのはそんなにバッキバキなことではなくDTPでやることを自動的にやるかんじで.
こんなんです
- マスターページに名刺っぽい台紙をつくっておいたinddファイルを開く(1ページ目はテンプレート)
- スクリプトのなかにオブジェクトをもっておいて,ひとつのデータにつき1ページ目のテンプレートを複製していく
- 各ページにあるテキストフレームからラベルのついたものをひっぱりだしてテキストをいれかえる
- X-1aなPDFを書きだしてinddファイルをとじる
InDesign CoffeeScripting from nbqx on Vimeo.
CoffeeScriptでかいたのはこんなかんじです.はてダだとまだシンタックスハイライトにCoffeeScript無いっぽいのでpythonにしときます
##お約束 file = new File("/path/to/sample.indd") app.open(file) doc = app.activeDocument tpl = doc.pages[0] ##このデータを… data = [ {name_jp:"唐 一郎", name_en:"Ichiro Kara", post:"会長"}, {name_jp:"唐 二郎", name_en:"Jiro Kara", post:"副会長"}, {name_jp:"唐 三郎", name_en:"Saburo Kara", post:"社長"}, {name_jp:"唐 四郎", name_en:"Shiro Kara", post:"副社長"}, {name_jp:"唐 五郎", name_en:"Goro Kara", post:"書記長"}, {name_jp:"唐 六郎", name_en:"Rock'n'Roll Kara", post:"副書記長"}, {name_jp:"唐 七郎", name_en:"Shichiro Kara", post:"代表取締役 専務"}, {name_jp:"唐 八郎", name_en:"Hachiro Kara", post:"資材部 リーダー"} ] ##Arrayから条件にあうものをひとつピック findOne = (a, fn) -> ret = [] ary = if a instanceof Array then a else [a] for v in ary if fn(v) then ret.push(v) if ret.length is 0 then null else ret[0] ##引数のなにかをコピペ copyAndPaste = (src) -> src.select() app.copy() app.paste() doc.selection[0] ##ラベルのついたテキストフレームを探して文字列をいれかえ proc = (page,data) -> post = findOne page.allPageItems, ((o) -> if o.label is "post" then true else false) name_jp = findOne page.allPageItems, ((o) -> if o.label is "name_jp" then true else false) name_en = findOne page.allPageItems, ((o) -> if o.label is "name_en" then true else false) if post? then post.contents = data.post if name_jp? then name_jp.contents = data.name_jp if name_en? then name_en.contents = data.name_en ##データごとにページを追加しつつ… for val in data p = doc.pages.add() for itm in tpl.allPageItems clone = copyAndPaste(itm) clone.move(p) clone.geometricBounds = itm.geometricBounds proc(p, val) ##X-1aなPDFを吐きだしてドキュメントを閉じる pdf = new File(doc.fullName.toString().replace(/\.indd$/,".pdf")) doc.exportFile(ExportFormat.PDF_TYPE,pdf,false,'[PDF/X-1a:2001 (日本)]') doc.close(SaveOptions.NO) alert('Done!')
でもってJavaScriptに吐きだしたやつ
(function() { var clone, copyAndPaste, data, doc, file, findOne, itm, p, pdf, proc, tpl, val, _i, _j, _len, _len2, _ref; file = new File("/path/to/sample.indd"); app.open(file); doc = app.activeDocument; tpl = doc.pages[0]; data = [ { name_jp: "唐 一郎", name_en: "Ichiro Kara", post: "会長" }, { name_jp: "唐 二郎", name_en: "Jiro Kara", post: "副会長" }, { name_jp: "唐 三郎", name_en: "Saburo Kara", post: "社長" }, { name_jp: "唐 四郎", name_en: "Shiro Kara", post: "副社長" }, { name_jp: "唐 五郎", name_en: "Goro Kara", post: "書記長" }, { name_jp: "唐 六郎", name_en: "Rock'n'Roll Kara", post: "副書記長" }, { name_jp: "唐 七郎", name_en: "Shichiro Kara", post: "代表取締役 専務" }, { name_jp: "唐 八郎", name_en: "Hachiro Kara", post: "資材部 リーダー" } ]; findOne = function(a, fn) { var ary, ret, v, _i, _len; ret = []; ary = a instanceof Array ? a : [a]; for (_i = 0, _len = ary.length; _i < _len; _i++) { v = ary[_i]; if (fn(v)) { ret.push(v); } } if (ret.length === 0) { return null; } else { return ret[0]; } }; copyAndPaste = function(src) { src.select(); app.copy(); app.paste(); return doc.selection[0]; }; proc = function(page, data) { var name_en, name_jp, post; post = findOne(page.allPageItems, (function(o) { if (o.label === "post") { return true; } else { return false; } })); name_jp = findOne(page.allPageItems, (function(o) { if (o.label === "name_jp") { return true; } else { return false; } })); name_en = findOne(page.allPageItems, (function(o) { if (o.label === "name_en") { return true; } else { return false; } })); if (post != null) { post.contents = data.post; } if (name_jp != null) { name_jp.contents = data.name_jp; } if (name_en != null) { return name_en.contents = data.name_en; } }; for (_i = 0, _len = data.length; _i < _len; _i++) { val = data[_i]; p = doc.pages.add(); _ref = tpl.allPageItems; for (_j = 0, _len2 = _ref.length; _j < _len2; _j++) { itm = _ref[_j]; clone = copyAndPaste(itm); clone.move(p); clone.geometricBounds = itm.geometricBounds; } proc(p, val); } pdf = new File(doc.fullName.toString().replace(/\.indd$/, ".pdf")); doc.exportFile(ExportFormat.PDF_TYPE, pdf, false, '[PDF/X-1a:2001 (日本)]'); doc.close(SaveOptions.NO); alert('Done!'); }).call(this);
まだCoffeeScriptだとこんなべんりにできるよーとか把握してなくてアレなのですが,とかくループのネストが凶暴な牙を剥きがちなCS系のJavaScriptでループがかなりスッキリするし,あと今回はつかってないんだけどHash(というかオブジェクトというかjsonというか)もforでkeyとvalueがひっぱってこれるのでスッキリするんじゃないかとおもいます.それと何気にelvis演算子が小気味いいとおもいました,これもけっこうちゃんとチェックするのメンドーだし.ただじぶんの場合,JavaScript書くときに三項演算子をけっこうつかうのでそれが"if xxx then yyy else zzz"になるのはちょっとなーとおもいました.そのためだけに"`"つかって生JSいれるのもアレだし…
しかしながら,まだがっつりつかっていこうってかんじではないけど可能性としてはありかもなとおもいました.
つかJavaScriptのエクリチュールとしてちょーおもろい