Illustratorで異なるフォントの高さを合わせるスクリプト

**※スクリプトだけ見たいと言う方は下の「終わりに」部分に飛んでください**

自分は仕事上名前と数字を並べるということが多いのですが、
高さを合わせるのが結構めんどくさいんですよね

例えば"Qiita 10"と言う文字列を作ろうとしてもベースラインの高さやバウンディングボックスの余白などが全然違うので目見当でバウンディングボックス大きさを変えてはドラッグして位置合わせする・・・という感じになります(下の画像はベースラインで合わせてます)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298776/87a5472b-6031-6428-067e-0b0cf4b4c19e.png)

##めんどくさいことは機械にやらせよう##

人力がめんどくさいんだったらスクリプトでやろう！と言うことでJavascriptで書こうと思ったのですが、
まずAdobe ExtendScript toolkitを使ったらこれがまた酷くて全然使えませんでした(´・ω・`)

公式でもサポートされてないっぽいのでVsCodeのExtendScriptプラグインを入れてそちらで編集しました

参考：
Adobe製品をVSCodeで制御(Javascript) - Qiita
https://qiita.com/mm_sys/items/917420a3a2eb9da96220

##フォントの高さを取得する##
Javascriptでフォントの高さを取得しようとしたんですが(自分が調べた限り)無いんですよね
バウンディングボックスの高さは取得できるのでいろいろ回り道しつつフォントの高さを取得します

まず選択からTextFrameを取得していろいろ処理するためにコピーしておきます

```javascript
var selAry = app.activeDocument.selection;

if (selAry.length == 0) {
    alert("テキストが選択されていません");
    throw new Error("テキストが選択されていません");
}

var textFrame0 = selAry[0]; // 文字部
var textFrame1 = selAry[1]; // 数字部

textFrame2 = textFrame0.duplicate(); // 文字をコピー
textFrame3 = textFrame0.duplicate();
```

バウンディングボックスの余白を消すためにアウトライン化します

```javascript
// アウトライン化する
outline2 = textFrame2.createOutline(false); 
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298776/309c680f-432c-e6f4-b086-0aba35297c08.png)

下の記事を参考にフチが余計なので削除・・・したいところですがなぜか消せません(なぜ？)

ASCII.jp：IllustratorもJavaScriptで自由自在に！ (4/4)
https://ascii.jp/elem/000/000/453/453500/4/

```javascript
alert(outline2.stroked);　// Undefinedになる
```

仕方ないのでフチがそのままで高さを取る方法が無いか調べたところ
visibleBoundsとgeometricBoundsというものがあり、
前者が見た目通りのbounds、後者が線などを除いたboundsになるようです

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298776/789ef94e-932d-441e-14f7-f609c66b19d8.png)
(青がvisibleBounds、赤がgeometricBounds)

これで文字の高さが取れるようになりました
ただし、画像ではQの下が飛び出しているので数字と高さを合わせると数字の下が飛び出してしまって都合が悪いです
なので頭文字の上端と2文字目以降の下端の高さを取得して高さを合わせる基準にします
2文字目以降もfgjpqyが含まれていると下が飛び出して困るので削除してから高さを取得します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298776/ea248dd2-6532-bc0a-7343-8bf7b6ee3649.png)


```javascript

var selAry = app.activeDocument.selection;

var textFrame0;
var textFrame1;
    
textFrame0 = selAry[0]; // 文字部
textFrame1 = selAry[1]; // 数字部

textFrame2 = textFrame0.duplicate(); // 文字をコピー
textFrame3 = textFrame0.duplicate();

head = textFrame2.contents; // 文字列を取得

textFrame2.contents = head.charAt(0); // 頭文字のみにする

head = head.substr(1); // 2文字以降

exString = "fgjpqy"; // 下が飛び出している文字を削除する

for (index = 0; index < exString.length; index++) {
    c = exString.charAt(index);
    if (head.indexOf(c) != -1) {
        head = head.substring(0, head.indexOf(c)) + head.substring(head.indexOf(c) + 1);
    }
}

textFrame3.contents = head; // 下が飛び出してる文字削除済

// アウトライン化する
outline2 = textFrame2.createOutline(false); 
outline3 = textFrame3.createOutline(false);

// geometricBoundsは線幅が含まれないので文字の高さを取得できる
// 頭文字の上部と2文字以降の下部から文字の高さを取得
var charHeight = outline2.geometricBounds[1] - outline3.geometricBounds[3];

// 文字部の中央Y位置を取得
var centerPos = (outline2.geometricBounds[1]+ outline3.geometricBounds[3]) / 2;

outline2.remove();
outline3.remove();

numFrame = textFrame1.duplicate();

numOutline = numFrame.createOutline(false);

// 数字の高さ
var numHeight = numOutline.geometricBounds[1] - numOutline.geometricBounds[3];

// 数字の中央Y位置を取得
var centerPosNum = (numOutline.geometricBounds[1]+ numOutline.geometricBounds[3]) / 2;

numOutline.remove();

```

##フォントの高さをそろえる##
これで文字部と数字部の高さが取得できたので大きさをそろえられます
文字の大きさを変えるにはresize()を、
移動させるにはtranslate()を使います

Illustrator JavaScript Reference イラストレーター JavaScript リファレンス
http://www.openspc2.org/reibun/Illustrator/ref/CompoundPathItem/method/resize/index.html

Illustrator JavaScript Reference イラストレーター JavaScript リファレンス
http://www.openspc2.org/reibun/Illustrator/ref/CompoundPathItem/method/translate/index.html


```javascript
// 大きさの違いの比率
ratio = charHeight / numHeight;

// ratioで拡縮して大きさを合わせる
textFrame1.resize(100 * ratio,100 * ratio);

// 文字と数字の高さを合わせる
textFrame1.translate(0,centerPos-centerPosNum);

```

これで完成です！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298776/82962b57-7513-3996-09af-00f44e664cd8.png)
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298776/25a17e9a-4c8a-b407-a716-bb8861480f25.png)

##終わりに##

スクリプト全体をここに折りたたんでおきます
<details><summary>サンプルコード</summary><div>

```javascript

var selAry = app.activeDocument.selection;

if (selAry.length == 0) {
    alert("テキストが選択されていません");
    throw new Error("テキストが選択されていません");
}

var textFrame0;
var textFrame1;
    
textFrame0 = selAry[0]; // 文字部
textFrame1 = selAry[1]; // 数字部

textFrame2 = textFrame0.duplicate(); // 文字をコピー
textFrame3 = textFrame0.duplicate();

textFrame2.translate(300,0); // 文字を移動
textFrame3.translate(500,00);

head = textFrame2.contents;

textFrame2.contents = head.charAt(0); // 頭文字のみにする

head = head.substr(1); // 2文字以降

    
exString = "fgjpqy"; // 下が飛び出している文字を削除する

for (index = 0; index < exString.length; index++) {
    c = exString.charAt(index);
    if (head.indexOf(c) != -1) {
        head = head.substring(0, head.indexOf(c)) + head.substring(head.indexOf(c) + 1);
    }
}

textFrame3.contents = head; // 下が飛び出してる文字削除済

// アウトライン化する
outline2 = textFrame2.createOutline(false); 
outline3 = textFrame3.createOutline(false);

alert(outline2.stroked);　// Undefinedになる

// geometricBoundsは線幅が含まれないので文字の高さを取得できる
// activeDocument.pathItems.rectangle(outline2.geometricBounds[1],0,100,outline2.geometricBounds[1]-outline3.geometricBounds[3]);
// 頭文字の上部と2文字以降の下部から文字の高さを取得
var charHeight = outline2.geometricBounds[1] - outline3.geometricBounds[3];

// 文字部の中央Y位置を取得
var centerPos = (outline2.geometricBounds[1]+ outline3.geometricBounds[3]) / 2;

outline2.remove();
outline3.remove();

numFrame = textFrame1.duplicate();

numOutline = numFrame.createOutline(false);

// 数字の高さ
var numHeight = numOutline.geometricBounds[1] - numOutline.geometricBounds[3];

// 数字の中央Y位置を取得
var centerPosNum = (numOutline.geometricBounds[1]+ numOutline.geometricBounds[3]) / 2;

numOutline.remove();

// 大きさの違いの比率
ratio = charHeight / numHeight;

// ratioで拡縮して大きさを合わせる
textFrame1.resize(100 * ratio,100 * ratio);

// 文字と数字の高さを合わせる
textFrame1.translate(0,centerPos-centerPosNum);

// ＼(＾o＾)／

```

</div></details>

作ってみようと思ってから完成するまで数年かかりました
それくらいAdobeのスクリプトって情報が少ないんですよね・・・

Illustrator Scripting | Adobe Developer Connection
https://www.adobe.com/devnet/illustrator/scripting.html

このリンク先の情報だけでは到底作れませんでした

あとExtendscript Toolkitのデバッガの出来が悪すぎたんでVsCodeに移行したら多少進捗が出るようになりました
そして変数が不定の言語でかつ情報が少ないとIDEの補完とか効かなくて地獄を見るって事がよくわかりました(´・ω・`)