【Lifehacks】InDesign文書を生成する

■タスク
・データファイルを元に定型的ページ構成のInDesign文書を自動生成する。


■目的
・ページ内のオブジェクト配置は単純だが、データが多いため手作業を少なくしたい。
・ページ構成が確定していないので、試行錯誤を行いたい。
・今後、様々な文書を生成する場合の雛形となるスクリプトを作りたい。


■仕様
スクリプトは、前処理、コンテンツ生成処理、後処理の関数に分ける。
・コンテンツ生成処理で参照するページ構成に必要な各種パラメータは、スクリプト先頭部分で定義する。
・コンテンツ生成処理の内容は、生成する文書に応じて書き換えることを想定。
・今回の例におけるデータファイル仕様は以下の通り。
  - データファイルはCSV形式。
  - データファイルは4つの項目を持つ。
  - 第1項目はテキストフレーム用の文字列。
  - 第2~4項目はイメージフレーム用の画像ファイル名。
  - 第2~4項目は空の場合あり。
・今回の例におけるページ仕様は以下の通り。
  - 表紙、中扉等、先頭に6頁。
  - 裏表紙、奥付等、末尾に4頁。
  - 先頭・末尾頁は頁生成のみスクリプトで実施。
  - 主要頁部は、4頁1組で、データファイルの各行が1組に対応する。


■備考
・画像貼り付け用テキストフレームはコンテントタイプをグラフィックに指定するが、テキストに指定した場合とフレームの位置が異なる。
 解消方法が不明のため、今回は場当たり的対応を実施。


■使用方法
・本スクリプトInDesignスクリプトネルフォルダに配置。
InDesignを機動し、スクリプトパネルから当該スクリプトを呼び出し。


■プログラム

//
// SgIdGenDocForPjXXX.jsx
// InDesign文書を生成する。
//
// Author: Orihika Ikuo
// Create: 2008.10.12
// Update: 2008.10.18
//

//// Constant /////////////////////////////////////////////////////////////
const PATH_SEP       = "/";
const ITEM_SEP       = ",";

const BASE_DIR       = "X:/Project/Project01";
const IMG_DIR        = BASE_DIR + PATH_SEP + "Image";
const DAT_FILE       = BASE_DIR + PATH_SEP + "Data.csv";

const FRONT_PG_NUM   = 6;
const BACK_PG_NUM    = 4;

const PG_W           = 105;
const PG_H           = 105;
const UNIT           = "mm";
const BINDING        = PageBindingOptions.leftToRight;

const TXT_FR_X       = 15;
const TXT_FR_Y       = 45;
const TXT_FR_W       = 75;
const TXT_FR_H       = PG_H - (2 * TXT_FR_Y);
const TXT_CHR_SZ     = "20Q";
const TXT_FONT       = "小塚ゴシック Pro	R";

const IMG_FR_X       = -20;
const IMG_FR_Y       = -20;
const IMG_FR_W       = 145;
const IMG_FR_H       = 145;
const IMG_SCALE_H    = 50;
const IMG_SCALE_V    = 50;

//// Main routine /////////////////////////////////////////////////////////
main();

function main() {
  var itemMatrix = SgIdLoadDat();

  var doc = SgIdPrologue();

  SgIdGenContent(doc, itemMatrix);

  SgIdEpilogue(doc);
}


//// Sub routine //////////////////////////////////////////////////////////
function SgIdLoadDat() {
  var itemMatrix = new Array();

  var myFile  = new File(DAT_FILE);
  var flgOpen = myFile.open("r");
  if (!flgOpen) {
    alert("Cannot open file.");
  }

  while(!myFile.eof) {
    var line     = myFile.readln();
    var itemList = line.split(ITEM_SEP);
    itemMatrix.push(itemList);
  }

  return itemMatrix;
}

function SgIdPrologue() {
  var doc = SgIdCreDoc();

  doc = SgIdAddBasicPages(doc);

  return doc;
}

function SgIdCreDoc() {
  var doc = app.documents.add();

  doc.viewPreferences.textSizeMeasurementUnits   = MeasurementUnits.q;
  doc.viewPreferences.horizontalMeasurementUnits = MeasurementUnits.millimeters;
  doc.viewPreferences.verticalMeasurementUnits   = MeasurementUnits.millimeters;
  doc.documentPreferences.pageWidth   = PG_W + UNIT;
  doc.documentPreferences.pageHeight  = PG_H + UNIT;
  doc.documentPreferences.pageBinding = BINDING;

  return doc;
}

function SgIdAddBasicPages(doc) {
  // 先頭頁の追加
  // デフォルト頁の分を減じて頁生成
  for(var i = 0; i < FRONT_PG_NUM - 1; i++) {
    doc.pages.add();
  }
  // 末尾頁の追加
  for(var i = 0; i < BACK_PG_NUM; i++) {
    doc.pages.add();
  }

  return doc;
}

function SgIdEpilogue(doc) {
//  doc.close(SaveOptions.yes);
}


//// Custom sub routine ///////////////////////////////////////////////////
//
// 文書仕様にあわせた内容とする。
// 本例:
// ・4頁1組
// ・1頁目にテキストフレーム
//   データ配列の1件目の文字列を入力
// ・2~4頁目にイメージフレーム
//   データ配列の2~4件目のファイルを配置
// ・データ配列の2~4件目は空の場合あり
//
function SgIdGenContent(doc, itemMatrix) {
  var pos = doc.pages.item(FRONT_PG_NUM - 1);

  for (var i = 0; i < itemMatrix.length; i++) {
    var itemList = itemMatrix[i];
    var pg0 = doc.pages.add(LocationOptions.after, pos);
    var pg1 = doc.pages.add(LocationOptions.after, pg0);
    var pg2 = doc.pages.add(LocationOptions.after, pg1);
    var pg3 = doc.pages.add(LocationOptions.after, pg2);
    var aryPg = [pg0, pg1, pg2, pg3];
    pos = pg3;

    if (itemList[0] != "") {
      SgIdAddTxtFrame(aryPg[0], itemList[0]);
    } else {
      alert("0th item is not there.");
    }

    for (j = 1; j < itemList.length; j++) {
      if (itemList[j] != "") {
        SgIdAddImgFrame(aryPg[j], itemList[j]);
      }
    }
  }
}

function SgIdAddTxtFrame(pg, str) {
  var x1 = TXT_FR_X;
  var y1 = TXT_FR_Y;
  var x2 = TXT_FR_X + TXT_FR_W;
  var y2 = TXT_FR_Y + TXT_FR_H;

  txtFrame = pg.textFrames.add();

  if (pg.side == PageSideOptions.rightHand) {
    x1 += PG_W;
    x2 += PG_W;
  }
  txtFrame.visibleBounds = [y1, x1, y2, x2];

  txtFrame.contentType   = ContentType.textType;
  txtFrame.contents      = str;
  txtFrame.paragraphs[0].appliedFont = app.fonts.item(TXT_FONT);
  txtFrame.parentStory.texts.item(0).pointSize = TXT_CHR_SZ;
  txtFrame.textFramePreferences.verticalJustification = VerticalJustification.centerAlign;
}

function SgIdAddImgFrame(pg, fileName) {
  var x1 = IMG_FR_X;
  var y1 = IMG_FR_Y;
  var x2 = IMG_FR_X + IMG_FR_W
  var y2 = IMG_FR_Y + IMG_FR_H;

  imgFrame = pg.textFrames.add();

  if (pg.side == PageSideOptions.rightHand) {
    x1 += PG_W;
    x2 += PG_W;
  }
  imgFrame.visibleBounds = [y1, x1, y2, x2];

  imgFrame.contentType   = ContentType.graphicType;
  imgFrame.place(IMG_DIR + PATH_SEP + fileName);
  imgFrame.horizontalScale = IMG_SCALE_H;
  imgFrame.verticalScale   = IMG_SCALE_V;
  imgFrame.fit(FitOptions.centerContent);
}