062.【Id】レイヤーを切り替えて複数回PDF書き出し
挙動
- 起動するとダイアログが立ち上がるので、書き出しプリセットを選択する
- ダイアログに表示されたレイヤー名を元に、以下のようなテキストデータを作成する
ページ範囲 [タブ] PDFファイル名1 [タブ] レイヤー1,レイヤー2
ページ範囲 [タブ] PDFファイル名2 [タブ] レイヤー1,レイヤー3,レイヤー4
ページ範囲 [タブ] PDFファイル名3 [タブ] レイヤー5 - 実行ボタンを押すと、指定したレイヤーのみが表示された状態でPDFが書き出される
- スクリプト実行前の状態に戻る
コード
//@targetengine "filterLayers" /* あらかじめ以下のようなテキストデータを作成する。 ページ範囲 [タブ] PDFファイル名1 [タブ] レイヤー1,レイヤー2 ページ範囲 [タブ] PDFファイル名2 [タブ] レイヤー1,レイヤー3,レイヤー4 */ var main = function() { app.scriptPreferences.enableRedraw = false; var doc = app.activeDocument; var ls = []; for (var i = 0, l = doc.layers; i < l.length; i++) { ls.push(l[i].name); } if (app.documents.length === 0) { alert("開いているドキュメントがないため中断します"); exitFlag = true; exit(); } // ウィンドウを作成 var dialog = new Window("dialog"); dialog.text = "レイヤー切り替えPDF書き出し"; dialog.orientation = "column"; dialog.alignChildren = ["center", "top"]; var group1 = dialog.add("group"); group1.orientation = "column"; group1.alignChildren = ["left", "top"]; var group2 = group1.add("group"); group2.orientation = "column"; group2.alignChildren = ["left", "center"]; var dropdown1 = dialog.add("dropdownlist", undefined, app.pdfExportPresets.everyItem().name); dropdown1.preferredSize.width = 500; var group3 = group1.add("group"); group3.orientation = "column"; group3.alignChildren = ["left", "center"]; var statictext2 = group3.add("statictext"); statictext2.text = "レイヤー一覧"; var edittext2 = group3.add('edittext {properties: {multiline: true, scrollable: true}}'); edittext2.text = ls.join(","); edittext2.preferredSize.width = 500; edittext2.preferredSize.height = 100; edittext2.multiline = true; var button1 = dialog.add("button"); button1.text = "実行"; button1.onClick = function() { dialog.close(1); } var dlgResult = dialog.show(); if (dlgResult !== 1) { alert("中断しました"); exitFlag = true; exit(); } var myList = fileReadInAppend("prange", "pname", "visibleLayers"); var cnt = myList.length; // ファイル名の重複チェック if (!chkDuplicates(myList, "pname")) { alert("ファイル名が重複しているため中断しました"); exitFlag = true; exit(); } if (!dropdown1.selection) { alert("書き出しプリセットが選択されていないため中断しました"); exitFlag = true; exit(); } var p = app.pdfExportPresets.itemByName(dropdown1.selection.text); for (var i = 0; i < cnt; i++) { doc.layers.everyItem().visible = false; for (var j = 0, vlcnt = myList[i].visibleLayers.length; j < vlcnt; j++) { try { doc.layers.itemByName(myList[i].visibleLayers[j]).visible = true; } catch (e) { alert("指定のレイヤーが存在しないため中断しました"); exitFlag = true; exit(); } } // ファイル名に使用できない文字チェック if (/[\*\?"<>\|]/g.test(myList[i].pname)) { alert("ファイル名に使用できない文字が含まれているため中断しました"); exitFlag = true; exit(); } var fn = doc.filePath + "/" + myList[i].pname + ".pdf".replace(".pdf.pdf", ".pdf").replace(".PDF", ""); app.pdfExportPreferences.pageRange = myList[i].prange; try { doc.exportFile(ExportFormat.pdfType, File(fn), false, p); } catch (e) { alert("存在しないページが指定されている等なんらかのエラーが発生しました。\n中断します。"); exitFlag = true; exit(); } } function fileReadInAppend(value1, value2, value3 /*string*/ ) { var tgtFile = File.openDialog("ファイルを選んでください", "*.txt"); if (!tgtFile || !tgtFile.exists) { alert("中断しました"); exitFlag = true; exit(); } var res = []; var fileReadFlag; tgtFile.open("r"); tgtFile.encoding = "UTF-8"; try { while (!tgtFile.eof) { var ln = tgtFile.readln().split(/\t/); if (ln.length !== arguments.length) { alert("読み込みテキストに不備があります。\n中断します。"); exit(); exitFlag = true; } var item = {}; item[value1] = ln[0]; item[value2] = ln[1]; item[value3] = ln[2].split(","); res.push(item); } fileReadFlag = true; } catch (e) { alert(e); fileReadFlag = false; } finally { tgtFile.close(); } if (!fileReadFlag || res.length === 0) { alert("ファイルを読み込めませんでした"); exit(); exitFlag = true; } return res; } // 配列内で同じプロパティを持つオブジェクトを抽出 function chkDuplicates(objArr, prop) { var exist = {}; var result = []; for (var i = 0, l = objArr.length; i < l; i++) { if (typeof objArr[i] !== "object") { continue; } var tmp = objArr[i][prop]; if (!exist[tmp]) { exist[tmp] = 1; } else if (exist[tmp] === 1) { exist[tmp]++; result.push(arr[i]); } else { exist[tmp]++; } } return result; } } var exitFlag = false; // main内で中断した場合に完了アラートを出さないようにするため app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.FAST_ENTIRE_SCRIPT, "filterLayers.jsx"); app.undo(); if (!exitFlag) { alert("完了しました"); }
メモ
分かったこと
doScriptでmain関数を呼ぶような書き方をしている場合、main関数内でexit()した後はdoScript以降の処理に移行する(ちょっと考えれば当たり前なんだけど…)。
積み残し
- ページ範囲指定
色んなページの指定の仕方があるのと、数値っぽい文字列を扱わなくちゃならないあたり、こんな単純な書き方で大丈夫かどうかちょっと不安。
もう少し考えておきたい。 - fileReadIn関数の引数
いくつ項目があっても対応できるようにしておきたい。
arguments.length分itemにプロパティを追加するかたちにするか、あるいは引数を配列でわたすか、かなあ。