HTML5でできるカメラアプリ・予習(2)-撮影から画像生成まで-

main.jpg
gayouさん、ありがとうございます。
というわけで、Android版Opera Mobile 12.00というバージョンで対応していることをこちらでも確認しました。
ただ、今回お話する「設定」の部分がTP(テクニカルプレビュー、前回から使っているアイコンに「LAB」がついたもの)と違いがあり、ちょっと混乱しそうなので、前回ダウンロードしたLAB付きのOpera Mobileを使ってチャレンジしてみたいとおもいます。
ではCSS Nite in OSAKA, Vol.30の予習記事その2ということで挑戦してみましょう。
さてこれまでで、AndroidのカメラからHTMLベースで写真を撮影することができました。こんどは、撮った画像をサーバにアップするために、img要素を生成しましょう。
まずは前回のとおり、撮影した映像をvideo要素に取り込みます。
今回は最終的にはそれをPHPに向けて送信するため、「video要素からcanvas要素に描画した画像をPNGやJPEG形式の画像に書き出す」までをおこないます。
ただし、AndroidのWebブラウザは通常それを許可していません。
色々な理由、セキュリティやプライバシーの問題もあってのことでしょう。
canvas要素にはtoDataURL()というJavaScriptの命令があります。
これでcanvas要素から画像を生成することができます。
しかし、これが許可されてないんです。
(Android、というよりブラウザで制御している、と言った方が正しいかも)
ただし、これはOpera Mobile上のコンフィグという「設定」で解除することができます。
実験的にこのtoDataURL()をつかいたい場合、まずはこれを解除しましょう。
URLに「opera:config」と入力します(最後にスラッシュはつけないでください)。
すると「設定ファイルエディタ」というページが表示されるはずです、下図を参照してください。
config01.png
config02.png
config03.png
ここでちょっと下にスクロールすると「Security Prefs」というタブがありますので、
「Allow Camera To Canvas Copy」という項目にチェックをいれます。
さらにその下の「保存」ボタンを押して下さい(結構忘れがちです)。
以上でOKです。
これでtoDataURL()が有効になり、canvas要素からPNGやJPEGのような画像が生成できます。
(注意!)
これは、テストが終わったらかならず設定で元に戻してください。
そうすればカメラの映像は外部に漏れることはないので、セキュリティ上、充分注意して使ってください。

ボタンが押されたらvideo要素からcanvas要素に静止画を書き出す

上記の設定が済んだら、撮った写真をcanvas要素に描画します。
以下のサンプルではbutton要素が押されたらvideo要素の画像をcanvas要素に描画します。

<!DOCTYPE HTML>

<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no">
<title>カメラの映像を映す!</title>
<style>
html, body, video {
margin: 0;
padding: 0;
}
video, canvas, button {
display: block;
}
</style>
<script>
function init() {
var video = document.getElementsByTagName("video")[0];
var canvas = document.getElementsByTagName("canvas")[0];
var ctx = canvas.getContext("2d");
navigator.getUserMedia("video", function (s){
video.src = s;
});
document.getElementsByTagName("button")[0].addEventListener("click", function () {
ctx.drawImage(video, 0, 0);
}, false);
}
</script>
</head>
<body onload="init()">
<button>撮影</button>
<video autoplay></video>
<p>▼ここからcanvas</p>
<canvas></canvas>
<p>▼ここからimg</p>
<img alt="canvasから書き出された画像" />
</body>

</html>

  

device.png
 
device4.jpg
もちろん、このとおりvideo要素とcanvas要素のサイズが合ってないので、実際完成させるにはこのサイズを同じにしてしまわないといけません。(今回は省略します)

canvas要素からJPEG画像をつくる

それではimg要素にcanvasの画像を出力します。
canvas要素にはtoDataURL()というメソッドが用意されています。
これを使うと、Base64と呼ばれる文字列が吐き出されます。
この長い文字列は、画像だけでなく、PDFファイルなど色々なファイルに置換できます。
ボタンを押されたときに、alert(canvas.toDataURL())を仕込むと下図のようにアラートが表示されます。これがBase64の文字列です。よく見ると、これはPNG形式の画像を文字列にした、ということがわかります。

今回はJPEG画像にするので、canvas.toDataURL(“image/jpeg”)とします。
省略するとPNG形式になるようです。

device3.png
これをこのままimg要素のsrc属性の値にすると、画像が表示されます。

<!DOCTYPE HTML>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no">
<title>カメラの映像を映す!</title>
<style>
html, body, video {
margin: 0;
padding: 0;
}
video, canvas, button {
display: block;
}
</style>
<script>
function init() {
var video = document.getElementsByTagName("video")[0];
var canvas = document.getElementsByTagName("canvas")[0];
var ctx = canvas.getContext("2d");
navigator.getUserMedia("video", function (s){
video.src = s;
});
document.getElementsByTagName("button")[0].addEventListener("click", function () {
ctx.drawImage(video, 0, 0);
document.getElementsByTagName("img")[0].src = canvas.toDataURL("image/jpeg");
}, false);
}
</script>
</head>
<body onload="init()">
<button>撮影</button>
<video autoplay></video>
<p>▼ここからcanvas</p>
<canvas></canvas>
<p>▼ここからimg</p>
<img alt="canvasから書き出された画像" />
</body>

</html>

device2.png
さて、これで「撮影して静止画をimg要素に書きだす」までできました。
次回はいよいよ、サーバ上にあるPHPにこの画像を送って保存しましょう。

HTML5でできるカメラアプリ・予習(1)

webrtc.png

こちらのイベント「CSS Nite in OSAKA, Vol.30」で実演する内容です。
将来はこういったことは現実に私達の仕事になってくると思われる、HTMLベースのカメラアプリ。
video要素やcanvas要素を使って撮った写真を加工してサーバに残す、なんてことは特にスマホ案件で依頼が来るかもしれません、そうなって焦らないように今から勉強しておきたいですね。
せっかくイベントで発表させてもらうので、これからシリーズでブログに書いていこうと思います、いまから勉強するのは決して早すぎることはないでしょう。

カメラアクセス、2つの仕様

まずはHTML5関連で、ブラウザからデバイスのカメラやマイクにアクセスする仕様は大きく2つあるように思えます。
WebRTC 1.0: Real-time Communication Between Browsers
The Media Capture API
どちらともスマホのカメラで写真が撮れて、保存したりできそうです。
ただしこの2つの仕様の目的はちょっと違うようです。
WebRTCのほうは文字どおり、リアルタイムコミュニケーションをブラウザ間にて可能にするというもの、つまりスカイプのHTML版のようなものです。

壮大なWebRTCのゆくえ

WebRTCの仕様のページを斜め読みするだけでも、その目的が壮大で、
カメラにアクセスすることだけが主な目的ではないようですね。
その目玉といえるのは「Peer-to-peer connections(ペアトゥーペアコネクション)」。
この仕様は、カメラで録りっぱなしの映像(動画)を、別の人のブラウザに届け、お互い映像のやりとりをおこなうことを目的としてるようです。

デモを試してみよう

zuhan.jpg
Opera mobileのテクニカルプレビューをAndroidスマートフォンにインストールしましょう。
以下のサイトの「Android Build」のリンクをタップしてダウンロードしてください。
「LAB」と書いてあるOperaのアイコンです、起動してください。
まずはこちらのページにアクセスしましょう。
これを動画で見るとこうなります。

Opera MobileでgetUserMedia from Hideki Akiba on Vimeo.

最低限ソースコードでカメラ撮影、でも向きを変えると縦横非がおかしくなる…
ソースコードもシンプルですし、意外と簡単です。

<!DOCTYPE HTML>
<html lang="ja">
     <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, user-scalable=no">
          <title>カメラの映像を映す</title>
     </head>
    
     <body>
         
          <video autoplay>
         
          <script>
               var video = document.getElementsByTagName("video")[0];
               navigator.getUserMedia("video", function (s){
                    video.src = s; // カメラ接続が成功したら、ストリームをvideo要素に接続
               });
          </script>
         
     </body>
</html>

navigator.getUserMediaというメソッドがカメラを取得するという役目を担います。
取得が成功したらvideo要素に映像ストリームを流すというものです。
注意としては、仕様書と、Opera Mobileの実装がコードを見るとちがいます。
将来は微妙に変わってくるでしょうが、基本的な原理の部分はほぼこのままでいてほしいです。
zuhan2.jpg
動画でもわかるとおりネイティブアプリのカメラ機能とちがい、できないことが多すぎます。
   * オートフォーカスの機能がつかえない
   * 撮影する写真の解像度を決めることができない
   * フラッシュなどの機能がつかえない
   * スマホの縦横の向きを変えると、映像の縦横比がおかしくなる
この、向きを変えたときに縦横比がおかしいのはちょっと使いにくいので、ちょっと工夫をこらしてみました。
もしもデバイスの向きが変わったら、一旦video要素に流れているストリームをとめて、
video要素のサイズをwindowのサイズにあわせた後にもう一度ストリームを流します。
どうしても、video要素を全体的に見せたい場合、横向きがこんな感じにしかならなかったんですが、これでなんとかなりそうです。

Opera MobileでgetUserMedia2 from Hideki Akiba on Vimeo.

今度は縦横比を修正しました
ソースコードは先ほどのものよりちょっと付け足しました。

<!DOCTYPE HTML>
<html lang="ja">
     <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, user-scalable=no">
          <script src="../common/js/jquery-1.7.1.min.js"></script>
          <title>カメラの映像を映す</title>
          <style>
           html, body, video {
                margin: 0;
                padding: 0;
           }
          </style>
     </head>
    
     <body>
    
     <video autoplay>
         
          <script>
               var video = document.getElementsByTagName("video")[0];
               var stream = null;
               navigator.getUserMedia("video", function (s){
                    video.src = stream = s;
               });
              
               $(window).bind('load orientationchange resize', function(e){
                    // デバイスの向きが変わったら...
                    video.src = null; //一旦ストリームを解除する
                    if(Math.abs(window.orientation) === 90){
                         video.width = window.innerWidth; //video要素のサイズを調整
                    }else{
                         video.height = window.innerHeight; //video要素のサイズを調整
                    }
                    video.src = stream; //再度ストリームを接続する
               });
          </script>
    
     </body>
</html>

まとめ

将来は、撮影機能つきのWebサイト制作があるかもしれません。
そうなると今までAndroidアプリ開発のために、XMLをコーディングしていたデザイナーも、これからはHTMLやCSSでデザインをする時代がくるわけですね、そう遠くもないでしょう。
今は本当にテストビルドなので、簡素な実装です。
もちろん本格的に実装なんかしたらセキュリティやプライバシーの問題があるので、「あること」をしないと画像として送信できないことになっています。
しかし今はこれで充分楽しめます。
オートフォーカスもできないのであればちょっと実用はむずかしいかな?と思いますが、こういった部分はどんどん使える実装になっていくんでしょうね、楽しみです。
この次は録った画像をcanvas要素に描画して、色々と画像を操作することにチャレンジしてみます。
今回の内容は2012年5月4日(金)に大阪で開催されるCSS Nite in OSAKA, Vol.30で実演します。
他にも、録った写真をサーバにアップしたり、モノクロにしたり、色々なデモをやってみますが、会場に来られた方でAndroidをお持ちの方は是非、今回のテスト版Opera Mobileをダウンロードしてお越しください。
結構ディレクターさんとかにも聞いてほしい内容です。
これからのWeb技術なので知っておいてソンはないと思いますので。
参加表明はお気軽にFacebookからおねがいします。

CSS3コードジェネレータ「Grad3 – Easy CSS3 gradient editor -」公開

og_img.png

前にもここで告知しましたが公開しました、Grad2の後継バージョン「Grad3 – Easy CSS3 gradient editor -」[ http://grad3.ecoloniq.jp/ ]です。

円形グラデーションにも対応させてますが、古いWebKitの仕様と新しいWebKitの仕様だと、お互いできることとできないことがあるので、円の中心座標だけ決めてしまうというもので進めていこうと考えてつくりました。
アイコンも付けられますが実際はみなさんで微調整してください。
background-positionは暫定でつけていますので。
あと、動画をつくってみました。

なお、CSS Nite in OSAKA, Vol.30でもちょっとだけ紹介したいとおもいます。

CSS Nite in OSAKA, Vol.30

これからもどうぞよろしくお願いします!