Windows上のターミナル内で画像を表示する(Sixel Graphics)

## 最初にまとめ

* 2025/04更新
  * Windows Terminal(1.22以降)がSixelグラフィックに対応しました(Git bashを単体で利用する必要がなくなりました)

* LinuxやMacでは様々なターミナルがSixelをサポートしていますが、~~Windowsで表示可能なターミナルが少なく~~、明確なやり方が見つからなかったのでまとめた

* git-bash環境に含まれるターミナル`mintty`で表示できる（Git Bashを単体で起動すればminttyで動いているのでOK。~~Windows Terminalに組み込んだgit-bashはNG~~）

* (Windowsで)画像からSixelのエスケープシーケンスを含むデータに変換するには、nodeのライブラリを使うのが簡単

  ソース一式 https://github.com/murasuke/windows-sixel

## Sixel Graphics とは
特別なエスケープシーケンスをキャラクターベースのターミナルに送信することで、画像を表示する技術です。

詳細は[Sixel グラフィックス - VT100.net: VT330/VT340 プログラマーリファレンスマニュアル](https://github.com/fumiyas/translation-ja/blob/master/vt3xx-sixel.md)をご確認ください。

通常のターミナルエミュレーターは[VT100](https://ja.wikipedia.org/wiki/VT100)互換ですが、Sixelを表示するためにはVT200以降の機能をサポートしている必要があります。

LinuxやMacでは様々なターミナルがSixelをサポートしていますが、Windowsではかなり限られるようです。

このあたりを調べて試した限りこの辺はうまくいきませんでしたが、もっと簡単な方法を見つけたのでメモを残します。
* [MSYS2](https://www.msys2.org/) 表示できず
* [VSCodeがSixelをサポート](https://zenn.dev/hankei6km/articles/display-images-on-vscode-terminal) 表示できず



## Windowsのターミナルで画像を表示する簡単、確実な手順

[git for Windows](https://gitforwindows.org/)環境に含まれるターミナル`mintty`がSixelをサポートしています。
　⇒`Git Bash（git-bash.exe）`がminttyを使っているので起動すればOK

手運

1. [git for Windows](https://gitforwindows.org/)のインストール

2. `Git Bash（git-bash.exe）`を起動して、(Sixcelのエスケープシーケンスに変換済みデータから)画像を表示できるか確認する

3. 画像ファイルからSixelのエスケープシーケンスに変換して、`Git Bash（git-bash.exe）`で表示する

  ※画像ファイルからの変換は`libsixel`というパッケージに入っている'img2sixel'コマンドを使うのが王道のようですが、Windowsではソースからのコンパイルが必要なので、node環境のライブラリを利用して変換します


### 1. [git for Windows](https://gitforwindows.org/)と[Node.js](https://nodejs.org/en/download/package-manager)インストール

[git for Windows](https://gitforwindows.org/)と、[Node.js](https://nodejs.org/en/download/package-manager)をダウンロードしてインストールします

### 2. `Git Bash（git-bash.exe）`を起動して(Sixcelのエスケープシーケンスに変換済みデータから)画像を表示できるか確認する

gitをインストールすると、`git bash`が利用できるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276579/5aa7dccd-3ce7-c4e3-9c03-a1ae2d5bbb0d.png)

サンプル画像データ(エスケープシーケンスを含むSixel変換後データ)をダウンロードして、カレントディレクトリに保存します
[mountain.sixel](https://github.com/murasuke/windows-sixel/blob/master/mountain.sixel)

catでファイルを開くと画像が表示されます


![image-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276579/03a1a5cc-65ec-2f7e-8c4a-2fcd66050fa8.png)



### 3. 画像ファイルからSixelのエスケープシーケンスに変換して、`mintty`で表示する

Windows上から簡単に利用できる、node環境のライブラリ[sixel](https://www.npmjs.com/package/sixel)を利用して変換します

* node版sixcel(とcanvas)をインストールする

```
mkdir node-sixel
cd node-sixel
npm init y
npm i sixel canvas
```

4. [img2sixel.js](https://github.com/murasuke/windows-sixel/blob/master/img2sixel.js) を作成する
https://github.com/jerch/node-sixel/blob/master/img2sixel.js
のコードを一部修正(require('./lib/index') ⇒ require('sixel/lib/index'))

```js:img2sixel.js
/**
 * Example script as cmdline converter.
 * Call: `node img2sixel.js <image files>`
 */

// set to 16 for xterm in VT340 mode
const MAX_PALETTE = 256;

// 0 - default action (background color)
// 1 - keep previous content
// 2 - set background color
const BACKGROUND_SELECT = 0;

const { loadImage, createCanvas } = require('canvas');
const {
  introducer,
  FINALIZER,
  sixelEncode,
  image2sixel,
} = require('sixel/lib/index');

async function processImage(filename, palLimit) {
  // load image
  let img;
  try {
    img = await loadImage(filename);
  } catch (e) {
    console.error(`cannot load image "${filename}"`);
    return;
  }
  const canvas = createCanvas(img.width, img.height);
  const ctx = canvas.getContext('2d');
  ctx.drawImage(img, 0, 0);

  // use image2sixel with internal quantizer
  const data = ctx.getImageData(0, 0, img.width, img.height).data;
  console.log(`${filename}:`);
  console.log(
    image2sixel(data, img.width, img.height, palLimit, BACKGROUND_SELECT)
  );

  // alternatively use custom quantizer library
  // const RgbQuant = require('rgbquant');
  // const q = new RgbQuant({colors: palLimit, dithKern: 'FloydSteinberg', dithSerp: true});
  // q.sample(canvas);
  // const palette = q.palette(true);
  // const quantizedData = q.reduce(canvas);
  // console.log(`${filename}:`);
  // console.log([
  //   introducer(BACKGROUND_SELECT),
  //   sixelEncode(quantizedData, img.width, img.height, palette),
  //   FINALIZER
  // ].join(''));
}

async function main() {
  let palLimit = MAX_PALETTE;
  for (const arg of process.argv) {
    if (arg.startsWith('-p')) {
      palLimit = parseInt(arg.slice(2));
      process.argv.splice(process.argv.indexOf(arg), 1);
      break;
    }
  }
  for (const filename of process.argv.slice(2)) {
    await processImage(filename, palLimit);
  }
}

main();

```

4. 'Git Bash（git-bash.exe）'を起動する

5. 動作確認
下記コマンドを実行する

```
$ node.exe img2sixel.js mountain.png
```

![image-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276579/15626283-4fcf-a186-e993-e3d87e37f6a3.png)

※nodeに拡張子`.exe`をつけないとうまく表示できない場合があるようです(多分ttyの問題だと思いますが、詳細はよくわからず）

https://mseeeen.msen.jp/what-does-winpty-command-do/

https://qiita.com/kimisyo/items/e6b9c453d5bb002f1486

## その他のやり方

* imagemagick で画像をsixcel形式に変換して表示
Windowsにはconvertというコマンドが入っているので、フルパスで指定すること
```
convert rose: sixel:
```

`libsixel`
mingw環境でコンパイルすれば動くらしい
https://github.com/saitoha/libsixel?tab=readme-ov-file#cross-compiling-with-mingw


https://qiita.com/yumetodo/items/4aa03d1eb3d887bca1a8