[HTML5] カメラをJSで操作し写真を撮影する

HTML5ではPCやスマホのデバイスの機能をJavaScriptから直接利用することができるようになりました。今回はカメラを操作し、デジカメのような要領で静止画を撮影する簡単なサンプルを作ってみたいと思います。

カメラの映像が向かって左側に写り続け、良いタイミングで下にある「シャッター」ボタンをクリックすると、右側に撮影した静止画が表示されます。ボタンをクリックするとシャッター音も再生されます。

サンプル

実行例

以下のページから実際にサンプルを実行できます。 miku3.net

初回のアクセス時にWebブラウザから、このサイトにカメラの操作を許可して良いか聞かれますので「許可」ボタンをクリックしてください。「ブロック」ボタンを押すと設定を変更するのにメニューの少し深いところに潜る必要がありますのでご注意を。

ソースコード

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Camera Test</title>
  <style>
  canvas, video{
    border: 1px solid gray;
  }
  </style>
</head>
<body>

<h1>HTML5カメラ</h1>

<video id="camera" width="300" height="200"></video>
<canvas id="picture" width="300" height="200"></canvas>
<form>
  <button type="button" id="shutter">シャッター</button>
</form>

<audio id="se" preload="auto">
  <source src="camera-shutter1.mp3" type="audio/mp3">
</audio>

<script>
window.onload = () => {
  const video  = document.querySelector("#camera");
  const canvas = document.querySelector("#picture");
  const se     = document.querySelector('#se');

  /** カメラ設定 */
  const constraints = {
    audio: false,
    video: {
      width: 300,
      height: 200,
      facingMode: "user"   // フロントカメラを利用する
      // facingMode: { exact: "environment" }  // リアカメラを利用する場合
    }
  };

  /**
   * カメラを<video>と同期
   */
  navigator.mediaDevices.getUserMedia(constraints)
  .then( (stream) => {
    video.srcObject = stream;
    video.onloadedmetadata = (e) => {
      video.play();
    };
  })
  .catch( (err) => {
    console.log(err.name + ": " + err.message);
  });

  /**
   * シャッターボタン
   */
   document.querySelector("#shutter").addEventListener("click", () => {
    const ctx = canvas.getContext("2d");

    // 演出的な目的で一度映像を止めてSEを再生する
    video.pause();  // 映像を停止
    se.play();      // シャッター音
    setTimeout( () => {
      video.play();    // 0.5秒後にカメラ再開
    }, 500);

    // canvasに画像を貼り付ける
    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
  });
};
</script>
</body>
</html>

解説

大まかな原理

navigator.mediaDevices.getUserMedia()が、引数として渡した連想配列の内容に従ってカメラからの映像をストリームとして持ってきてくれます。このストリームを<video>要素にそのまま流し込んでいます。「シャッター」ボタンをクリックすると、押した瞬間の<video>の内容を画像として取り出し、<canvas>にそのまま貼り付けているだけです。

サンプルではボタンをクリックすると一瞬止まりますが、その方がデジカメ感があるため演出として付けているだけで、不要であればvideo.pause();からsetTimeout()あたりのコードを削除すれば処理その物は一瞬で終わります。

カメラが存在しない場合は?

navigator.mediaDevices.getUserMedia()が例外を発生、.catch()で捕捉されます。 ここではフロントカメラを指定していますが、もしリアカメラを指定しリアカメラがない機器の場合は同様にエラーが返される可能性があります。

オプション

特に指定しない

単に映像と音に対し利用するかどうかBooleanで指定するだけです。

  const constraints = {
    audio: false,
    video: true
  };

解像度の最小値と最大値

サンプルのようにwidth,heightの値を固定することもできますが、minで最小値、maxで最大値を指定することもできます。

  const constraints = {
    audio: false,
    video: {
       width: { min: 800, max: 1920 },
      height: { min: 600, max: 1080 }
    }
  };

またidealという指定もできます。直訳すると「理想」という意味ですが、idealで指定した解像度になるべく近い映像を返すよう努力してくれます。

  const constraints = {
    audio: false,
    video: {
       width: { min: 800, ideal: 1280, max: 1920 },
      height: { min: 600, ideal:  720, max: 1080 }
    }
  };

素材

SE(シャッター音)
効果音ラボ https://soundeffect-lab.info/

参考ページ