スマートフォンでカメラ画像を取得し JavaScript でエフェクト掛けてみた(その2:getUserMedia編)


# ■はじめに
前回は Camera API を利用して撮影した写真にエフェクトを掛けるところまでを行いました。
Firefox OSでの写真撮影には Camera API 以外にも getUserMedia と mozCamera があり、今回は getUserMedia を使用しての方法を行ってみたいと思います。

# ■getUserMedia

いきなり最初に書くのもアレなのですが、 Firefox OS での getUserMedia は問題点がいくつかあります…

- <b>その1: <font size=3>解像度が小さい</font></b>  
Firefox のシミュレータでは綺麗な画像を取得できるのですが、 Firefox OS の実機( Flame, Fx0 )では取得した画像の解像度が小さくなります。表示時に倍角に引き伸ばしている模様で、荒く表示されますorz
- <b>その2: <font size=3>W3C のフルスペックの仕様に対応していない</font></b>  
[W3C の仕様](http://www.w3.org/TR/mediacapture-streams/#media-track-constraints
)では取得時の縦横のサイズ、アスペクト比、フレームレートなどが指定出来ますが、そもそもで Firefox では対応していない要素もあるため、Firefox OS でも同様に指定できません。  
[仲さんの資料](http://www.slideshare.net/yusukenaka52/getusermedia)にまとまっていますのでご参照ください。  
※最新の状態では変わっている可能性もありますが。ただし、少なくとも Fx0 では縦横のサイズを指定しての取得は出来ません。

``` W3C_spec
dictionary MediaTrackConstraintSet {
    ConstrainLong      width;
    ConstrainLong      height;
    ConstrainDouble    aspectRatio;
    ConstrainDouble    frameRate;
    ConstrainDOMString facingMode;
    ConstrainDouble    volume;
    ConstrainLong      sampleRate;
    ConstrainLong      sampleSize;
    ConstrainBoolean   echoCancellation;
    ConstrainDOMString deviceId;
    ConstrainDOMString groupId;
};
```

いきなりデメリットから入ってしまいましたが、この API を使用するのはとても簡単というのが最大のメリットでもあります。
そのため、このデメリットを活かすようにアプリを作ってしまえば良いかなっと思います。
例えば、解像度の低さを利用してトイカメラを作るとか、解像度を要求しないサービスに使えます。また、Web 権限で動作するので、自分の Web サイトにおくことができますので、マーケットを利用する必要はなくなります。

## manifest

というわけで使い方に入りたいと思います。

getUserMediaで動画キャプチャするには、マニフェストファイルのpermissionsに以下の定義を追加する必要があります。

```
  "permissions": {
    "video-capture": {
      "description": "Required to capture video via getUserMedia" 
    }
  }
```

## 処理フロー

<img src="https://qiita-image-store.s3.amazonaws.com/0/27642/abba1ee2-bec9-241b-29e9-0679ce54552e.png" width=70%>

1. getUserMedia で撮影した画像を video 要素に渡す
2. video 要素から canvas に静止画として画像を貼り付ける
3. canvas から jpeg として取り出し、 img 要素に設定する
4. エフェクト処理をする。

という流れになります。
静止画を取得するのに canvas にわざわざ貼り付けています。
私が調べた範囲では getUserMedia を利用した場合、静止画を取得する API がありませんでした。
その為、取得するのに canvas 経由で画像を取得しています。

## getUserMedia から video 要素へ

カメラから撮影した画像を video 要素に渡すことで、撮影対象をプレビューすることができます。

```
  navigator.getUserMedia = (navigator.getUserMedia || navigator.mozGetUserMedia);

  if (navigator.getUserMedia) {
    navigator.getUserMedia (
      { video: true },
      function onSuccess(stream) {
        var video = document.querySelector('video');
        video.src = window.URL.createObjectURL(stream);
        video.play();
      },
      function onError(err) {
        console.log('error');
      }
    );
  }
```

<img src="https://qiita-image-store.s3.amazonaws.com/0/27642/645aaddf-50f1-5011-13ac-139ad8def548.png" width=60%>


## video 要素から canvas へ

video 要素に表示されている画像を canvas 経由で静止画として取り出すには、context.drawImage()を使用すれば OK です。

## canvas から jpeg へ

canvas から jpeg 形式の画像を取得します。

```
  var image = canvas.toDataURL();
  document.getElementById(エフェクト対象画像のID).src = image;
```

## シャッター音を鳴らす

実は、ここに記載した getUserMedia から canvas 経由で jpeg 画像を取得するシャッター音は鳴りません。

その為、取得時に自分で鳴らす必要があります。
鳴らすには Audio API を使うと簡単に鳴らすことが出来ます。


今回作成したサンプルでは以下のサイトの素材を使用しました。
http://www.soundoffice.com/se/item/se-033.php


## エフェクト処理

<b>エフェクト処理前</b>
<img src="https://qiita-image-store.s3.amazonaws.com/0/27642/645aaddf-50f1-5011-13ac-139ad8def548.png" width=60%>

<b>エフェクト処理後</b>
Seriously.js で vignette を掛けています。
<img src="https://qiita-image-store.s3.amazonaws.com/0/27642/1e2184eb-37a5-df76-b98f-2532e9e388de.png" width=60%>


# ■まとめ

getUserMedia を使用して写真〜エフェクトまで実現しました。
ただ、最初に記載しましたが、画像が荒く、使うにはユースケースを考える必要があります。
とは言え、非常に簡単に使用できるので、ユースケースに合致すれば有用な方法かもしれません。

次回は mozCamera 編です。