デザイン自動化（InDesign基本編）

InDesignをJavaScriptで制御する際に基本になる詰まりどころをまとめていきます。
※ちょっとずつ追記していく予定です。

##開発環境（ExtendScript Toolkitを使います）
注意点。
起動後にソースコードを実行する対象アプリケーションを選択する必要があります。

##JAVASCRIPTコンソールに文字を出力する。
プログラムの試行錯誤時にコンソールに変数情報を出力すると何かと便利です。

```js
//改行なし
$.write("Hello World!!!!!");
//改行あり
$.writeln("Hello World!!!!!");
```

JAVASCRIPTコンソールの表示内容をクリアしたり、文字の大きさを変更するには右上のプルダウンを選択します。
下図の赤枠で囲った部分です。

![スクリーンショット-2018-09-08-17.10.25.jpg](https://qiita-image-store.s3.amazonaws.com/0/139650/5a6ffcc2-63b2-873c-9dc4-951dcad0f5e0.jpeg)

##フォルダー操作の基本

###フォルダー選択画面を表示してフォルダーを選ぶ

```js
var folderObj = Folder.selectDialog ();
$.writeln(folderObj.fsName);
```

備考：InDesignで定義されているFileオブジェクトやFolderオブジェクトはフォルダーの区切り文字がWindowsとmacOS両方で/（スラッシュ）で統一されているようです（macOS 10.13 InDesignCS5、Windows10 InDesign CCで確認）。

###サブフォルダ／サブファイルを取得する

```js
var folderObj = Folder.selectDialog ();
var subFolderObjList = folderObj.getFiles();

for (var i = 0; i < subFolderObjList.length; i++) {
    
    $.writeln(subFolderObjList[i].fsName); 
}
```

実行結果
![スクリーンショット 2018-09-08 22.36.14.png](https://qiita-image-store.s3.amazonaws.com/0/139650/31aac252-a594-d2bd-50e4-86ced80d7773.png)

##テキストファイル処理

###テキストファイルを読み込む

```js
function main() {
    var text_content = "";

    f = new File("/Users/efla/Desktop/test/test.xml");
    if (fh = f.open("r")) {
            text_content = f.read();
            f.close();
    }

     $.writeln(text_content);
}

main();
```

実行結果
![スクリーンショット 2018-09-29 19.52.32.png](https://qiita-image-store.s3.amazonaws.com/0/139650/87cfdefb-168e-78a3-a64b-33491d8a56c8.png)

##XMLファイルの操作

###XMLファイルの中身を取り出す。

色々な文法でXMLのパースができます。

####ソースコードにXML構造をゴリゴリ書く。

```js
function main() {
    var text_content = "";

    f = new File("/Users/efla/Desktop/test/test.xml");
    if (fh = f.open("r")) {
            text_content = f.read();
            f.close();
    }

     $.writeln(text_content);

     var xml_contents = new XML(text_content);
     
     for (i=0;i<xml_contents.Text.length();i++) {
         $.writeln(xml_contents.Text[i]);
     }
}

main();
```

実行結果
![スクリーンショット 2018-09-29 20.05.34.png](https://qiita-image-store.s3.amazonaws.com/0/139650/f41a63e7-6a88-8359-cd19-07a50ba3811f.png)

####XPathを使う

```js
function main() {
    var text_content = "";

    f = new File("/Users/efla/Desktop/test/test.xml");
    if (fh = f.open("r")) {
            text_content = f.read();
            f.close();
    }

     $.writeln(text_content);

     var xml_contents = new XML(text_content);
     
     for (i=0;i<xml_contents.xpath ("/Text").length();i++) {
         $.writeln(xml_contents.xpath ("Text")[i]);
     }
}

main();
```

実行結果
![スクリーンショット 2018-09-29 20.05.34.png](https://qiita-image-store.s3.amazonaws.com/0/139650/46b882ae-acf1-c3cd-23df-14ce86ce4498.png)

####属性値を取り出す

メソッドattributeでノードの属性値を取得できます。

```js
function main() {
    var text_content = "";

    f = new File("/Users/efla/Desktop/test/test.xml");
    if (fh = f.open("r")) {
            text_content = f.read();
            f.close();
    }

     $.writeln(text_content);

     var xml_contents = new XML(text_content);

     for (i=0;i<xml_contents.Text.length();i++) {
         $.writeln(xml_contents.Text[i]);
         $.writeln(xml_contents.Text[i].attribute("color"));
     }
}

main();
```

実行結果

![スクリーンショット 2018-09-30 9.27.29.png](https://qiita-image-store.s3.amazonaws.com/0/139650/f64e33aa-f9b4-57ce-4a65-03252d4789ed.png)

##InDesignドキュメントとファイル操作

###ファイパスを指定してInDesignファイルを開く

```js
function main() {

   // ドキュメントを開く
   f = new File("/Users/efla/Desktop/test.indd");
   doc = app.open(f);
   
   $.writeln(doc);
}

main();
```

###新規InDesignドキュメントを作成・保存・閉じる

```js
function main() {

   // 新規ドキュメントを作成する
   doc = app.documents.add();
  
   $.writeln(doc);
   
   // 新規ドキュメントを保存する
   doc.save("/Users/efla/Desktop/hoge.indd");
   // 新規ドキュメントを閉じる
   doc.close();
}

main();
```

##PDF出力

###アクティブドキュメントをPDFファイルに書き出しする。

####既定のプリセットで書き出す。

```js

function main() {

    app.activeDocument.exportFile(ExportFormat.pdfType, "/Users/efla/Desktop/hoge.pdf", false);
 }

main();
```

####プリセットを指定して書き出す。

```js
function main() {

    presetName = "[PDF/X-1a:2001 (日本)]";
    app.activeDocument.exportFile(ExportFormat.pdfType, "/Users/efla/Desktop/hoge.pdf", false,presetName);
 }

main();
```

##文字列操作

###正規表現と完全一致するか調べる。

```js
function main() {

    Str = “0987”

    if (/^[0-9][0-9][0-9][0-9]$/.test(Str)) {
       alert(“correct”);
    }
 }

main();
```

##画像操作

###画像をドキュメントに配置する。

```js
function main() {

   pageObj = app.activeDocument.pages[0];
   
   var imageObj = pageObj.textFrames.add();
   imageObj.visibleBounds = ["10mm","10mm","30mm","30mm"];
   imageObj.contentType = ContentType.graphicType;
   imageObj.place(new File("/Users/efla/Desktop/IMG_1453.png"));
   imageObj.fit(FitOptions.fillProportionally);
}

main();
```

結果
![スクリーンショット 2018-10-20 19.12.55.png](https://qiita-image-store.s3.amazonaws.com/0/139650/2747187c-8060-fd89-fa99-de55aaa2b1c4.png)

###画像のリンク情報を取得する

```js
function main() {

   pageObj = app.activeDocument.pages[0];
   
   var imageObj = pageObj.textFrames.add();
   imageObj.visibleBounds = ["10mm","10mm","30mm","30mm"];
   imageObj.contentType = ContentType.graphicType;
   imageObj.place(new File("/Users/efla/Desktop/IMG_1453.png"));
   imageObj.fit(FitOptions.fillProportionally);
   
   var glist = imageObj.allGraphics; 
 
   for (i=0;i<glist.length;i++) {
       
          g = glist[i];
          l = g.itemLink;
          $.writeln(g.itemLink.name);   // リンク先のファイル名取得
          $.writeln(l.filePath);              // リンク先のファイルパスを取得
   }  
}

main();
```

結果
![スクリーンショット 2018-10-21 7.06.31.png](https://qiita-image-store.s3.amazonaws.com/0/139650/2c3337d5-5104-4799-22eb-0a2c707ddc89.png)

###画像のメタ情報・位置情報を取得する

```js
function main() {

   pageObj = app.activeDocument.pages[0];
   var glist = pageObj.allGraphics; 
 
   for (i=0;i<glist.length;i++) {
       
          var g = glist[i];                              // Imageオブジェクト
          var l = g.itemLink;                         // Linkオブジェクト
      
          $.writeln(g);
          $.writeln(l);
          $.writeln(g.itemLink.name);       // リンク先のファイル名取得
          $.writeln(l.filePath);                  // リンク先のファイルパスを取得
          $.writeln(g.imageTypeName);    // リンクファイルの形式を取得
          
          $.writeln(g.absoluteHorizontalScale);
           $.writeln(g.absoluteVerticalScale);
          $.writeln(g.absoluteRotationAngle);
          $.writeln(g.absoluteShearAngle);
          
          $.writeln(g.horizontalScale);
          $.writeln(g.verticalScale);
          $.writeln(g.rotationAngle);
          $.writeln(g.shearAngle);
          
          $.writeln(g.visibleBounds);
          
          $.writeln(g.actualPpi);
          
          $.writeln(g.clippingPath);
   }  
}

main();
```

結果
![スクリーンショット 2018-10-21 18.30.06.png](https://qiita-image-store.s3.amazonaws.com/0/139650/3e2ff91e-9194-da4c-3494-6d9ddd88bb31.png)

##文字組処理

###テキストフレームを作成

```js

function addSwatch(c,m,y,k,name) {

   var i=0;

   for (i=0;i<app.activeDocument.colors.length;i++) {
        if (app.activeDocument.colors[i].name==name) {
            app.activeDocument.colors[i].remove();
        }
   }

   colorOption = {colorValue:[c,m,y,k],model:ColorModel.process,space:ColorSpace.cmyk,name:name}
   colorObj = app.activeDocument.colors.add(colorOption);    
 
   return colorObj;
 }

function main() {
    
    // 新しいテキストフレームを追加する。
    var tf = app.activeDocument.pages[0].textFrames.add();
    // テキストフレームの位置と大きさをページの左上を原点とする絶対座標で指定する。
    tf.visibleBounds = ["0mm","0mm","10mm","30mm"];
    // テキストフレームを移動させる（ページの左上を原点とする絶対座標）
    tf.move(["5mm","5mm"]);
    // テキストフレームを移動させる（今の位置から移動距離を指定）
    tf.move(undefined,["2mm","2mm"]);
    // テキストフレームに文字列を設定する。
    tf.contents = "みすずちんにはは";
    
    // 文字のQ数を指定する
    tf.paragraphs[0].characters[0].pointSize = "24Q";
    //テキストフレームを黒で塗りつぶす
    var s1 = addSwatch (0, 0, 0, 100, "黒");
    tf.fillColor = s1;
    // 文字の色とフォントを変更
    var s2 = addSwatch (0, 0, 0, 0, "白");
    var s3 = addSwatch (100,0,0,0, "C100");
    for (i = 0; i < tf.paragraphs[0].characters.length;i++) {
       tf.paragraphs[0].characters[i].strokeColor = s2;
       tf.paragraphs[0].characters[i].fillColor = s3;
    }
    // 文字のフォントを変更
    var f = app.fonts.item("ヒラギノ丸ゴ Pro");
    tf.paragraphs[0].appliedFont = f;
}

main();
```

結果（画像は別記画像処理で追加）

![スクリーンショット 2018-11-04 13.34.29.png](https://qiita-image-store.s3.amazonaws.com/0/139650/fdae5937-f36a-0003-3116-faade9c92914.png)

## 選択

スクリプトを作るときに、選択の解除や吟味をする処理を入れておかないと、トラブルの元になりやすい。

### 現在の選択をクリアする

```js
function main() {

    app.select(NothingEnum.nothing);
 }

main();
```

### 全てのオブジェクトを選択する

```js
function main() {
    
    // 必要に応じて、ロックオブジェクトやロックレイヤーの状態を調整する    
    
    app.select(SelectAll.all);   // 全てのオブジェクトを選択する
}

main();
```

### 現在の選択で、テキストフレーム以外の選択を解除する。

```js
function main() {

    var sel = app.activeDocument.selection;
    for (i=0;i<sel.length;i++) {
       
       if ( sel[i].contentType!=ContentType.textType ) {

          sel[i].select(SelectionOptions.removeFrom);
       }
    }
 }

main();
```

## コピー＆ペースト

### 選択しているオブジェクトをコピーペーストする

```js
function main() {

    try {
        app.copy();
        app.paste();
    } catch(e) {
        
     alert(e);
    }
 }

main();
```

結果（オブジェクトを選択している時）

![スクリーンショット 2018-11-11 17.17.30.png](https://qiita-image-store.s3.amazonaws.com/0/139650/9ab086ff-6a92-2994-cb29-9360473eea53.png)

結果（オブジェクトを選択していない時）

![スクリーンショット 2018-11-11 17.18.20.png](https://qiita-image-store.s3.amazonaws.com/0/139650/62e05e06-b879-e995-8d67-2df1f43f0389.png)

### 選択しているオブジェクトを同じ位置にペーストする

```js
function main() {

    try {
        app.copy();
        app.pasteInPlace();
    } catch(e) {
        
     alert(e);
    }
 }

main();
```

結果

![スクリーンショット 2018-11-11 17.32.51.png](https://qiita-image-store.s3.amazonaws.com/0/139650/a26fae0d-8b59-9e45-0b29-f499312c192d.png)

## レイヤー操作

### レイヤー情報を取得する

```js
function main () {

    var lList = app.activeDocument.layers;

    for (i = 0; i < lList.length;i++) {
    
        $.writeln(lList[i].name);    // レイヤー名
        $.writeln(lList[i].locked);   // レイヤーロック状態 
        $.writeln(lList[i].visible);   // レイヤー表示非表示状態
    }
}

main();
```

実行結果

![スクリーンショット 2018-11-11 22.03.24.png](https://qiita-image-store.s3.amazonaws.com/0/139650/40a94c68-a23e-cb64-7415-ccd7aae803f2.png)

## 線を扱う

### 線に矢印があるかどうか確認する

```js
function main() {
 
    var pageObj = app.activeDocument.pages[0];
    var total = pageObj.allPageItems.length;

    var i = 0;

    for (i=0;i<total;i++) {

       var pageItem;

       pageItem = pageObj.allPageItems[i];

       var typeName = pageItem.constructor.name;

        if (typeName=="GraphicLine") {
        
            $.writeln(typeName);
            $.writeln(pageItem.leftLineEnd.constructor.name);
            
            $.writeln(isDoubleHeadArrow (pageItem));
            $.writeln(isArrow(pageItem));
            
            //ArrowHead.NONE
            //ArrowHead.SIMPLE_ARROW_HEAD
            //ArrowHead.SIMPLE_WIDE_ARROW_HEAD
            //ArrowHead.TRIANGLE_ARROW_HEAD
            //ArrowHead.TRIANGLE_WIDE_ARROW_HEAD
            //ArrowHead.BARBED_ARROW_HEAD
            //ArrowHead.CURVED_ARROW_HEAD
            //ArrowHead.CIRCLE_ARROW_HEAD
            //ArrowHead.CIRCLE_SOLID_ARROW_HEAD
            //ArrowHead.SQUARE_ARROW_HEAD
            //ArrowHead.SQUARE_SOLID_ARROW_HEAD
            //ArrowHead.BAR_ARROW_HEAD
        }
    }
}

function isDoubleHeadArrow( item )  { 
    
    var typeName = item.constructor.name;
    
    if (typeName != "GraphicLine") {
        
        return false;1
   }

   if (item.leftLineEnd!=ArrowHead.NONE && item.rightLineEnd != ArrowHead.NONE) {
   
        return true;
   }

    return false;
}

function isArrow( item )  {
    
    var typeName = item.constructor.name;
    
    if (typeName != "GraphicLine") {
        
        return false;1
   }

   if (item.leftLineEnd != ArrowHead.NONE || item.rightLineEnd != ArrowHead.NONE) {
   
        return true;
   }

    return false;
}

main();
```

矢印の対比

<img width="412" alt="スクリーンショット 2018-12-24 23.10.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/139650/7dea7771-558d-5433-733d-6ba63e297dbd.png">