iTermのウインドウサイズの変化による背景画像の引き伸ばしを防ぐ

- 2019/06/17 更新
    - iTerm2 v3.3.0で実装された背景画像を自動調整する機能について言及しました

# TL; DR
- iTerm2のbeta版を使うことに抵抗が無い場合
    - v3.3.0で背景画像を自動調整する機能が追加されたのでそれ使いましょう
- stable版を使いたい場合
    - あらかじめ背景画像をアスペクト比毎に用意
    - JXAでiTermのウインドウサイズを取得しアスペクト比を算出、対応する背景画像に切り替え
    - 一定時間ごとに上記の処理を実行することで、iTermのウインドウサイズの変動に合わせて自動で切り替え(てるように見せる)

# iTermは背景画像が設定できる
MacOSのターミナルエミュレーターであるiTermは、よくある黒背景や白背景のような単色背景や透過設定だけでなく、画像を壁紙のように設定できる機能があります。
自分は下画像のように所謂「痛ターミナル」のような画像を設定していますが、これはこれで可愛いキャラクターを見ながら作業できるので作業が捗る（気がします）。

<img width="50%" alt="スクリーンショット 2017-11-07 12.50.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/169260/6a39c2b9-e0a7-d1bf-fd4e-2bdefc98e9a0.png" align="center">



この背景画像の設定ですが、iTermのウインドウサイズを変更した場合、画像の一部がはみ出て表示されるという訳ではなく、ウインドウサイズに合わせて画像が引き伸ばされます。

<img width="50%" alt="スクリーンショット 2017-11-07 12.51.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/169260/fe64251b-538c-5888-2524-5e98eb945a59.png">


画像によっては大して気にならないと思いますが、可愛いキャラクターが上下左右に引き伸ばされるのはあんまり見栄えが良くないなーと感じたので、ウインドウサイズを変えても背景画像が引き伸ばされずに表示されるような方法を考えました。

**2019/06/17 追記**
iTerm2のバージョン3.3.0で、ウインドウに対して背景画像をどのように表示させるかを選択するための設定項目がプロファイルの設定画面の`Window` -> `Background Image`に追加されました。
これを`Scale to Fill` に設定すれば下に示してあるような作業をせずとも一発で解決します。

![スクリーンショット 2019-06-17 21.05.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/169260/ad9de73a-1eb9-ffd4-0f3e-fce2c10fc6b4.png)

バージョン3.3.0は6月17日現在、iTerm2の安定リリース版では利用できずテストリリース版でしか利用できません。
安定リリース版と比べて不安定なリリースであることに注意して利用しましょう。
テストリリース版は[iTermの公式ダウンロードページ](https://www.iterm2.com/downloads.html)の「Test Releases」の項から取得できます。

**2019/06/17 追記終了**


# 1. 背景画像をアスペクト比毎に用意
背景画像をトリミングしてアスペクト比別に画像を用意します。
ここでは画像のファイル名は
`"(iTermのプロファイル名)_(縦の長さを1.00とした時の横の長さ).png"`
で統一しています。

<img width="903" alt="スクリーンショット 2017-11-07 13.36.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/169260/fca51a63-0601-c55e-6177-4ffc3e4d8596.png">

# 2. JXAでiTermの背景画像を設定
JXAでiTermのウインドウサイズを取得して、用意した画像群から最適な画像を選択して背景画像に設定します。

JXAに関しては詳しい説明は割愛しますが、JavaScriptを利用して、AppleScriptと同様にアプリケーションを制御することができます。

```js:bg_optimizer.js
// 用意した画像の縦横比(縦方向の長さを1とした時のに対する横方向の長さ)
var ratio_cands = [0.5, 0.6, 0.7, 0.8, 0.9,
                   1.0, 1.1, 1.2, 1.3, 1.4,
                   1.5, 1.6, 1.7, 1.8, 1.9,
                   2.0, 1.33, 1.78];

if (Application("iTerm").running()){

  // アクティブなiTermウインドウの縦横の長さを取得する
  var iTerm        = Application("iTerm");
  var window       = iTerm.currentWindow;
  var windowBounds = window.bounds();
  var width        = windowBounds.width;
  var height       = windowBounds.height - 25; // tab barが約25pxなので減算

  // ウインドウの縦横比を計算
  var ratio  = width/height;

　　　　// iTermのウインドウの縦横比に対して、用意した画像の縦横比から最も近い値を取得
  var nearest_val  = null;
  var minimum_diff = Number.MAX_VALUE;
  for (var i = 0; i < ratio_cands.length; i++) {
    var diff = Math.abs(ratio_cands[i] - ratio);
    if (diff < minimum_diff) {
      nearest_val = ratio_cands[i];
      minimum_diff = diff;
    }
  } 

　　　　// 背景画像を設定
  var profile_name    = window.currentSession.profileName();　　　　　　　　　　// TアクティブiTermウインドウのプロファイル名
  var current_bg_path = window.currentSession.backgroundImage(); // 現在の背景画像の絶対パス
  var bg_dirpath      = current_bg_path.substring(0, current_bg_path.lastIndexOf("/"));　　// 背景画像のディレクトリの絶対パス

  window.currentSession.backgroundImage = 
　　　　　　bg_dirpath + "/" + profile_name + "_" + nearest_val.toFixed(2) + ".png";
}
```

iTermを起動した状態で上記のスクリプトを実行すると、その時のiTermのウインドウサイズに合わせて背景画像が変更されます。

```shell-session
$ osascript -l JavaScript bg_optimizer.js
```

# 3. (optional) iTermのウインドウサイズの動的な変化に対応

ここまでの方法だと、ウインドウサイズを変更する度に逐一手動でスクリプトを実行する必要がありますが、いくつかの方法でウインドウサイズの変化を検出してスクリプトを自動で実行することができます。

### 3.1. fish-shellの--on-variableオプションを利用する
fish-shellを使用している場合、`--on-variable`オプションと環境変数`$COLUMNS`を利用することでウインドウサイズの動的な変化に対応できます。

`--on-variable`オプションは関数を宣言するときに利用できるオプションで、指定した環境変数の値が変化したときに関数を自動で実行します。
`$COLUMNS`は使用しているターミナルの横幅（1行に表示できる半角文字の数）を保持する環境変数で、ウインドウサイズが変わるとそれに応じて値が変わるため、この環境変数の値をチェックすることでウインドウサイズの変化を検出できます。

上記の`--on-variable`と`$COLUMNS`を利用して、背景画像を変更する関数`bg_auto_resize`を、ウインドウサイズが変わる度に自動で呼び出されるように定義する例を以下に示します。

```fish:config.fish
function bg_auto_resize --on-variable COLUMNS
    osascript -l JavaScript bg_optimizer.js
end
```

### 3.2 一定時間ごとにスクリプトを実行する
以下コマンドのようにバックグラウンドで一定時間毎に上記のスクリプトを実行するようにすれば一応、作業中にウインドウサイズをころころ変えてもその都度、最適な背景画像に変更してくれます。

```shell-session
$ while true; do `osascript -l JavaScript bg_optimizer.js`; sleep 5; done &
```
スクリプト内で`delay(5);`とかやっても良いと思います。
ただしウインドウサイズを変更しない間は無駄な処理を延々と繰り返してることになるので、あんまり良い方法では無いかなと思います。


# 参考
- [知らないうちにMacがシステム標準でJavaScriptで操作できるようになってた (JXA)](https://qiita.com/zakuroishikuro/items/1b02378bf9e940602d87)
- [動的にiTerm2の背景画像を変える](https://gist.github.com/STAR-ZERO/5928936)
- [JavaScript for Automation Cookbook](https://github.com/JXA-Cookbook/JXA-Cookbook/wiki)
- [全訳！fishシェル普及計画](http://fish.rubikitch.com/)

作成したスクリプトはこちらから。
https://gist.github.com/inside-hakumai/8456c4e003c069adc1435be0f4c2a2e2

# 最後に
真白ちゃん可愛い