ごんれのラボ

iOS、Android、Adobe系ソフトの自動化スクリプトのことを書き連ねています。

【実績紹介】デジタル・アド・サービス様 InDesign用スクリプト納品

概要

デジタル・アド・サービス様にInDesign用のスクリプトを2案件納品させていただきましたので、問題のない範囲でどういったスクリプトか、工夫した点はどこかなどをご紹介します。
また汎用的に使えそうな部分(&コアじゃない部分)の処理の一部はスクリプトを記載しています。
なお、この記事の内容はデジタル・アド・サービス様の許可をいただいています。

どういったスクリプトを納品したか

どちらのスクリプトもカタログの組版データから、必要な情報をテキストファイルに書き出すというものです。
ひとつは表組内の製品番号と同行にある価格を走査して製品番号と一緒にテキストファイルに抜き出し、もうひとつは製品番号が含まれる表組のページ内の面積占有率を計算してテキストファイルに抜き出します。

工夫した点

製品番号をページ内からどう検索するかについて

この処理は製品番号が含まれているテキストフレームの構造を理解する必要がありました。
該当するテキストフレームはページ内に存在し、かつ表組みが含まれているものであると仮定して、その条件にマッチするテキストフレームを抽出し、配列化しました。
また、あわせてページ内のテキストフレームを左上から右下に向かって並び替える処理も行っています。

実装したスクリプトの一部を以下に掲載します。

/**
 * Tableを含むTextFrameを抽出
 * @param  {Array} txFrames TextFrameの配列
 * @return {Array}          TextFrameの配列
 */
function extractTxFrameContainingTable(txFrames) {
    var result = [];
    for (var i = 0, txFrameLen = txFrames.length; i < txFrameLen; i++) {
        if (txFrames[i].tables.length > 0) {
            result.push(txFrames[i]);
        }
    }
    return result.length > 0 ? result : undefined;
}

/**
 * pageオブジェクト内のTextFrameを抽出して座標順にソート
 * @param  {Page} currentPage Pageオブジェクト
 * @return {Array}            TextFrameの配列
 */
function extractTxFrameInPage(currentPage) {
    var tfsArray = [];
    for (var i = 0, len = currentPage.allPageItems.length; i < len; i++) {
        var pageItem = currentPage.allPageItems[i];
        if (pageItem.constructor.name == 'TextFrame') {
            tfsArray.push(pageItem);
        }
    }
    return sortObjectsByCoordinateOrder(tfsArray);

    /**
     * 座標順(昇順)にソート
     * @param  {Collection} objects 座標値をもつオブジェクトのコレクション
     * @return {Array}              ソートした配列
     */
    function sortObjectsByCoordinateOrder(objects) {
        var sorted = objects.concat();
        sorted.sort(function (a, b) {
            // Y軸比較
            if (a.geometricBounds[0] < b.geometricBounds[0]) {
                return -1;
            }
            if (a.geometricBounds[0] > b.geometricBounds[0]) {
                return 1;
            }
            // X軸比較
            if (a.geometricBounds[1] > b.geometricBounds[1]) {
                return 1;
            }
            if (a.geometricBounds[1] == b.geometricBounds[1]) {
                return 0;
            }
            return -1;
        });
        return sorted;
    }
}

製品番号から価格を走査する処理について

この処理はInDesignの機能である正規表現検索と、表組のセル内のテキストを走査することで実現しました。
ここの処理がこの案件の要ともいえる部分で、結構苦労しましたし、何度かゼロから書き直したりしました。

正規表現検索

製品番号や価格は一定のルールで構成されているため、そのルールに則り正規表現のパターンをいくつか用意して配列化し、その配列分の検索を繰り返して検索を行いました。
また、その際に精度をあげるため段落スタイルも検索条件に加えました。こちらはドキュメント内のすべての段落スタイルの中から、製品番号や価格に使われているであろうスタイル名をもとに抽出して配列化しています。スタイルグループにも対応しました。

表組のセル内のテキスト走査

「製品番号と価格が同行にある価格を抜き出す」という条件があったので、それを実現するために製品番号を上述した正規表現検索で検索して、ヒットした製品番号が含まれているセルから右にあるセルを順番に処理し、その中に価格が含まれていたら抽出する処理を実装しました。
また、追加要件として製品番号と同行に価格がなかったら次の行にある価格を走査して抽出するという要望があったので、そちらもさくっと実装しました。

面積計算の前準備スクリプトについて

製品番号ごとの面積占有率を計算するにあたりオペレーターの作業が必要になるため、前準備スクリプトを実装しました。
このスクリプトは既存のドキュメントに対して以下のような処理を行います。

  • 段落スタイルを作成
  • レイヤーを作成
  • オブジェクトスタイルを作成
  • スウォッチを作成
  • フレームをひとつ作成して、オブジェクトスタイルとスウォッチを適用

このスクリプトのルールに則っていないフレームは処理の対象外とすることとし、後述する面積計算の処理をどのフレームに対して行えばよいかを明確にできました。

面積占有率計算について

ページ内の特定のレイヤーに存在する特定のオブジェクトスタイルが適用されているフレームを対象に、ページ内の面積占有率を計算しました。
また、上記のフレームの上に重なるように採番用のIDを流し込んだテキストフレームを作成し、IDは面積占有率やページ内の何番目のフレームかがわかるように、スクリプト内で自動生成しました。

その他

ワークフローや仕様要件の提案

対面やSlackでの打ち合わせをしたときに既存のワークフローをお聞きして、スクリプトでどう効率化するのかの提案や仕様要件の提案を行いました。
とはいえ、スクリプトを書ける担当者様からのご依頼だったので、

担「こんな風にスクリプトでできると思うのですが可能ですか?」
私「できますね。難しいとおっしゃってたこのパターンもこういう条件なら対応できますが、そういう処理で大丈夫ですか?」
担「いいですね!それでいきましょう!」

といった感じにスムーズに提案を受け入れていただいて、手戻りがあまり発生せずに進めることができました。
また、仕様要件や成果物であるテキストファイルの仕様、使い方をドキュメントとして納品しました。

処理の共通化

二案件同時にご依頼があったこともあり、処理の共通化を念頭において仕様要件を決めました。
結果的に製品番号を検索する処理、テキストを抽出する処理、レイヤーのロックを解除する処理、テキストファイルを保存する処理、スタイルを検索する処理と、ほとんどの処理を共通化できました。
ライブラリとしてincludeすることも検討したのですが、スクリプト単体で運用できるほうが取り回しやすいだろうということで、ライブラリ化は見送りました。

Undoの履歴に残らないようにした

大量の処理を行うので、Undoの履歴に残らないように doScript() を利用しました。

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

最後に

デジタル・アド・サービス様に納品したInDesign用スクリプトについてご紹介しました。
快く実績紹介に応じてくださったデジタル・アド・サービス様、ありがとうございました。