MGO2のクランエンブレム作成するやつ作った


<img src="https://user-images.githubusercontent.com/9010553/34260618-f15272fc-e6a9-11e7-9833-4bd5d4bafd1c.png" width="50%">

※そもそも、`MGO2`とはメタルギアオンラインというゲームです。  

## ソースとサイト
- [ソース](https://github.com/t4y3/mceg)
- [デモ](https://t4y3.github.io/mceg/)


## 作成方法の参考サイト(Windows向け)
- http://www.nicovideo.jp/watch/sm4949882
- http://cloud312.ldblog.jp/archives/50461688.html

## なぜ作るか
- Mac向けの参考サイトがない
- 各ツールを駆使して作れなくもないが面倒。
  - →ツール作るか。webで。

## なにで作るか
- [`parcel`](https://parceljs.org/) + `babel` + `node-scss`
  - parcelを使ってみたかった

## 実装について

### やることは大きく分けて4つ
- 画像を`32*32`にリサイズ
  - MGOのエンブレムサイズが`32*32`
- 16色に減色
  - MGOのエンブレムで使用できる色が16色
- 選択色ごとにハイライト表示
  - 最終的にはゲーム画面でぽちぽち手打ちする必要があるため、同色がどこに使われているかわかりやすくする
- カラーコードの表示を`8.21`で割る
  - MGOでエンブレムを作成する際のカラーピッカーが`0〜31`のため

### 画像選択
- ドラッグアンドドロップまたは、選択されたファイルを[`FileReader API`](https://developer.mozilla.org/ja/docs/Web/API/FileReader)で読み込み
- ファイル選択は`change`、ドラッグアンドドロップは`drop`イベントでデータを取得
- 読み込んだファイルデータをcanvasに書き出し  

```js
  // イベント設定
  uploadArea.addEventListener('change', (e) => {
    this.changeHandler(e);
  });
  uploadArea.addEventListener('dragenter', (e) => { e.preventDefault(); });
  uploadArea.addEventListener('dragover', (e) => { e.preventDefault(); });
  uploadArea.addEventListener('dragleave', (e) => { e.preventDefault(); });
  uploadArea.addEventListener('drop', (e) => {
    e.preventDefault();
    this.changeHandler(e, e.dataTransfer.files[0]);
  });

  /**
   * 画像アップロード時のcallback
   */
  changeHandler(e, data) {
    // drag and dropの場合は e.dataTransfer.files[0] を使用
    let file = data === undefined ? e.target.files[0] : data;

    let image = new Image();
    let fileReader = new FileReader();

    fileReader.onload = (e) => {
      let base64 = e.target.result;

      image.onload = () => {
        this.canvasCropper.width = image.width;
        this.canvasCropper.height = image.height;
        let originalCtx = this.canvasCropper.getContext('2d');

        // s:sourceImage, d:destinationCanvas
        // ctx.drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)
        originalCtx.drawImage(image, 0, 0, image.width, image.height, 0, 0, image.width, image.height);
      };
      image.src = base64;
    };

    fileReader.readAsDataURL(file);
  }
```

### クロッピング
- [Cropper.js](https://fengyuanchen.github.io/cropperjs/)を使用
- エンブレムは正方形なので`aspectRatio`は`1`に指定
- crop時のイベント引数からクロップ時のサイズ・位置が取得できるので  
crop範囲だけ別の`32*32`サイズのcanvasに描画

```js
  this.cropper = new Cropper(canvas, {
    aspectRatio: 1,
    preview: '.cropper-preview__img',
    crop: (e) => {
      ctx.drawImage(canvas,
        e.detail.x,
        e.detail.y,
        e.detail.width,
        e.detail.height,
        0,
        0,
        CANVAS_SIZE,
        CANVAS_SIZE
      );
    }
  });
```

### メディアンカット(中央値分割法)による減色
- ~~[`node-kmeans`](https://github.com/Philmod/node-kmeans)を使用~~
- [`mediancut`](https://github.com/t4y3/mediancut)を使用
- クロッピング時に作成した`32*32`サイズのcanvasのピクセルデータを取得して減色を行う

```js
let imagedata = ctx.getImageData(0, 0, CANVAS_SIZE, CANVAS_SIZE);

// reduced color (減色)
let medianCut = new MedianCut(imagedata);
medianCut.run(16);
```

### 減色後の表示
- クラスタリング後のデータで16色に減色されたカラーコードを取得して、canvasに描画して終わり

### 最後に
- MGO2全盛期の7〜8年前に作れていれば。。。
- TODOもたくさん。。。