【CSS】半透明(透明度)の設定方法 【お家IT#14】
本件の実装の一部
motojapan.hateblo.jp
前回の続き
motojapan.hateblo.jp
目次
前回は、レイアウトの重ね合わせを実装した。
今回は、ボタンの透過度を設定したい。
完成イメージ
前回からの続きだが、ボタンが透過して下レイヤーの映像をスルーするようにしたい。
実装
opacityで設定することができる。
前回までに追記。
.my_btn{ … background: #668ad8; opacity: 0.8; /*0-1の範囲で不透明度を設定*/ … }
【Javascript / CSS】divタグでcanvas等のレイアウトを重ねる方法 【お家IT#13】
本件の実装の一部
motojapan.hateblo.jp
前回の続き
motojapan.hateblo.jp
目次
前回は、カメラ撮影枠を作成するために、カメラリソースの切り替えによるVideo要素のサイズ変化を検出した。
今回は、実際にカメラ撮影枠を作るためのレイアウトの重ね合わせ方法についてまとめる。
完成イメージ
こんなものを作りたい。
カメラのプレビュー上に、撮影領域と撮影ボタンを配置したい。
基本方針
- 基本的な枠組みは、HTMLのdiv要素とCSSでレイアウトの重ね合わせ。
- 動的なレイアウトプロパティの変更は、JavascriptからCSSの設定を変更。
div要素で重ねわせ方法と実装
ポイント
重ねわせで重要なのはCSSのposition。
下記の設定を行う。
外側のparent | position: relativeに設定。 |
内側のl1~l3 | 特定の位置に置きたい場合、position: absoluteに設定。 |
特に今回は、
- l1は、video要素があり、動画ストリームが確定すると自動的にサイズが決まる
- l2は、l1のサイズのサイズに応じて、動的にサイズが決まる
となる。
実装
動的にCSSプロパティを操作する場合、2つの方法がある(style / setAttribute)
実装は下記の通り。
//**************** html ********************** <div class="parent" width="720px"> <div class="l1"> <video id="camera" width="720px" autoplay></video> </div> <div class="l2"> <canvas id="camera_record_box"></canvas> </div> <div class="l3"> <a id="take_picture" href="#" class="my_btn">TAKE PICTURE</a> </div> </div> //**************** css *********************** <style type="text/css"> .parent { width: 720px; height: 0px; position: relative; /*relativeに設定*/ border: 3px solid black; padding: 0em 0em; margin:0; } .l1 { /*前回の話の通り、動画ストリームが確定してから自動的にサイズが決まる*/ top: 0px; left: 0px; width: 720px; padding: 0em 0em; } .l2 { top: 0px; /*動的に変更されるので適当*/ left: 0px; /*動的に変更されるので適当*/ width: 400px; /*撮影枠サイズ*/ height: 60px; /*撮影枠サイズ*/ position: absolute; /*absoluteに設定*/ padding: 0em 0em; } .l3 { bottom: 0px; /*下端に配置*/ position: absolute; /*absoluteに設定*/ padding: 0em 0em; } #camera_record_box{ position: absolute; /*absoluteに設定*/ border: 1px solid red; /*赤い撮影枠*/ padding: 0em 0em; } </style> //************ javascript ******************** //関数でCSSの設定を操作する //(前回に追記) <script type="text/javascript"> function notify_change_size() { video_layout_width = video.clientWidth video_layout_height = video.clientHeight var element_parent = document.getElementsByClassName('parent'); var element_l2 = document.getElementsByClassName('l2'); var element_box = document.getElementById('camera_record_box'); box_width = 400 //box size box_height = 60 //box size left = (video_layout_width - box_width) / 2 top = (video_layout_height - box_height) / 2 //parentへの設定 for(var i=0, l=element_parent.length; i<l; i++){ element_parent[i].style.width = String(video_layout_width) + "px"; element_parent[i].style.height = String(video_layout_height) + "px"; } //l2への設定 for(var i=0, l=element_l2.length; i<l; i++){ //今回はi=0のみ element_l2[i].style.left = String(left) + "px"; element_l2[i].style.top = String(top) + "px"; element_l2[i].style.width = String(box_width) + "px"; element_l2[i].style.height = String(box_height) + "px"; } //camera_record_boxへの設定 element_box.setAttribute("width", String(box_width) + "px"); element_box.setAttribute("height", String(box_height) + "px"); } videoElement.onresize = notify_change_size; </script>
結果
上手くいった。
以上。
次回はボタンを透過したい。
【Javascript】カメラ起動前後のvideoタグのサイズ変化を検出する 【お家IT#12】
本件の実装の一部
motojapan.hateblo.jp
前回の続き
motojapan.hateblo.jp
目次
前回は、UserMediaのカメラリソースを切り替えるなどの話をした。
今回は、カメラリソースの切り替えによるVideo要素のサイズ変化を検出したい。
例えばインカムからアウトカムに切り替えるとき、解像度が異なると、Video要素のサイズが変わる。
もう少しわかりやすく具体例を出して説明する。
具体例:Video要素のプレビューの中央に撮影領域を作りたい
例えば、下図のようにVideo要素のプレビューの中央に撮影領域を作りたい。(赤い枠線部分)
これを作る場合、少なくともVideo要素のサイズ変化を検出してレイアウト確定時のサイズを求める必要がある。
実装:Video要素のサイズ変化を検出、確定時のサイズを取得
実は知っていればめちゃくちゃ簡単
//**************** html ********************** <video id="camera" width="720px" autoplay></video> //************ javascript ******************** //動的に取得する関数 <script type="text/javascript"> function notify_change_size() { var video = document.getElementById('camera'); video_layout_width = video.clientWidth video_layout_height = video.clientHeight } var videoElement = document.querySelector('video#camera'); //onresizeメッセージのコールバック関数を設定する videoElement.onresize = notify_change_size; </script>
以上。
次回はこの具体例を少し掘り下げてどうやってVideo要素でのプレビュー上に撮影領域を作るか考える。
【Javascript】カメラ(インカメラ/アウトカメラ)を切り替える方法 【お家IT#11】
本件の実装の一部
motojapan.hateblo.jp
前回の続き
motojapan.hateblo.jp
目次
前回からWebカメラ周り(Video要素やwebRTC, UserMedia)の操作を進めていたが、カメラリソース周りを今回進める。
やりたいことはWebアプリでのスマホカメラ起動なのでフロントカメラ、バックカメラの切り替えを行いたい。
MediaDeviceInfoの解説とUserMediaの使い方手順
上を読めばカメラだけでなくマイク、スピーカーのUserMedia周りの実装が分かるし、私が纏めるまでもないが、
重要なのは、”navigator.mediaDevices.enumerateDevices()”。
この関数の戻り値は、フロントエンド側でアクセス可能なI/Oメディアデバイスの情報(MediaDeviceInfoオブジェクトの配列)である。(Promise Object)
MediaDeviceInfoには下記の情報が含まれている。
label | デバイス名(Macなら”FaceTime HD Cam” とか) |
deviceId | 同一セッション内で一貫したデバイスID (セッションが切れるとrefresh) |
groupId | 物理デバイス単位でのグループID |
kind | videoinput / audioinput / audiooutput |
手順としては次の3つ
1) navigator.mediaDevices.enumerateDevices()でdeviceIdを取得
2) 1をvideoのdeviceIdと指定し、navigator.mediaDevices.getUserMediaでstreamを取得
3) 2のstreamをwindow.stream / video elementのstreamに代入
以上。
次回は、カメラ起動前後のvideoタグのサイズ変化を検出する。
【Javascript】video/canvasを上下180度反転(回転)させる方法 【お家IT#10】
本件の実装の一部
motojapan.hateblo.jp
前回の続き
motojapan.hateblo.jp
目次
前回までの投稿でバックエンドとフロントエンドの通信周りは整理した。
ここからはWebカメラの操作を進める。
今回は、video/canvasを上下180度反転(回転)させるたい。
原因は、Windowsタブレットのカメラが上下反転して表示されてしまう。(ハードウェア原因)
スマホなら問題ないのだが、気持ち悪いので補正する。
Videoの回転
HTML5&CSS3の組み合わせで、webkitのtransform rotationを使えば回転可能
回転中心は、Video領域の中心である
//**************** html ********************** <video id="camera" width="720px" autoplay></video> //**************** css *********************** <style type="text/css"> .Rotate0{ -webkit-transform: rotate(0deg); } .Rotate180{ -webkit-transform: rotate(180deg); } </style> //************ javascript ******************** //関数から動的に変更する <script type="text/javascript"> function rotate_video(degree) { var video = document.getElementById('camera'); //スタイルを適用する関数を定義 video.className = "Rotate"+degree; } //元の画像から180度反転する rotate_video(180) //元の画像に戻る rotate_video(0) </script>
Canvasの回転
Canvasの回転はテクニックが必要で、
単純にCanvasのcontextをrotateすると回転中心が(x, y) = (0, 0)つまり、左上部になってしまい、Canvasの中心では回転しない。
なので、translate(移動1) -> rotate(回転) -> translate(移動2)の手順で意図した回転になる。
移動1は、Canvas中心が(x, y) = (0, 0)になるように、画像半分の縦横長で移動
移動2は、Canvas中心が移動1実行前の位置に戻す為に、移動1と同じだけ反対方向に移動
今回はcanvasを回転させてから、videoタグの画像を張り付けるようにします。
//**************** html ********************** <canvas id="canvas"></canvas> //**************** css *********************** //不要 //************ javascript ******************** //関数から動的に変更する <script type="text/javascript"> function rotate_canvas(degree) { var canvas = document.getElementById('canvas'); //canvasの描画モードを2sに var ctx = canvas.getContext('2d'); //Canvasに設定するサイズを決める //(例えば、videoの縦幅横幅を取得) var video = document.getElementById('camera'); var w = video.offsetWidth; var h = video.offsetHeight; //同じサイズをcanvasに指定 canvas.setAttribute("width", w); canvas.setAttribute("height", h); //一旦canvasをリセットしたければ //ctx.clearRect(0, 0, canvas.width, canvas.height); //[移動1] Canvas中心が(x, y) = (0, 0)になるように、画像半分の縦横長で移動 ctx.translate(w/2, h/2); //[回転] ctx.rotate(degree * Math.PI / 180); //[移動2] Canvas中心が移動1実行前の位置に戻す為に、移動1と同じだけ反対方向に移動 ctx.translate( -1 * w/2, -1 * h/2 ); //videoの画像をcanvasにコピー ctx.drawImage(video, 0, 0, w, h); } //元の画像から180度反転する rotate_canvas(180) //元の画像に戻る rotate_canvas(0) </script>
以上。
次回はカメラ切り替えを予定。
【flask to Javascript】jsonデータを送信/受信する方法(jsonify) 【お家IT#9】
本件の実装の一部
motojapan.hateblo.jp
前回の続き
motojapan.hateblo.jp
目次
前回までで、javascript->flaskへbase64を送信した。
これを画像処理して、その結果を返信するときjsonだと汎用性も高い。
なのでjsonデータの返信方法をメモ。
送信側実装 (python:flask)
flaskのjsonifyを使うと簡単。
from flask import Flask, request, abort, make_response, current_app, jsonify ... @app.route('/hoge_image_processing', methods=['POST']) @crossdomain(origin='*') def image_processing(): ... res = { 'ip_type' : 'OCR', # 画像処理タイプ 'result' : 'hogehoge', # 画像結果 'prefix' : '201701011200' # 時刻プレフィクス } return jsonify(ResultSet=res) ...
受信側実装 (javascript)
いままでの続きに追記です。
重複部分はある程度省略。
#ajax用モジュール読み込み <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> <script type="text/javascript"> ... function send_img(){ ... #ajax送信 $.ajax({ //画像処理サーバーに返す場合 url: 'https://192.168.0.100:12345/hoge_image_processing', type: 'POST', data: fData , contentType: false, processData: false, success: function(data, dataType) { //非同期で通信成功時に読み出される [200 OK 時] //console.log('Success', data); if (data.ResultSet.ip_type == 'OCR') { var res = data.ResultSet.result; // 'hogehoge' var prefix = data.ResultSet.prefix; // '201701011200' } }, error: function(XMLHttpRequest, textStatus, errorThrown) { //非同期で通信失敗時に読み出される console.log('Error : ' + errorThrown); } }); } ... </script>
以上。
ここまでの4回の投稿でバックエンドとフロントエンドの通信周りは整理されたので、次回からはWebカメラの操作(反転、カメラ切り替え、サイズ変化検出)を進める。
【flask】Replyヘッダーに「Access-Control-Allow-Origin」を追加する【お家IT#8】
本件の実装の一部
motojapan.hateblo.jp
前回の続き
motojapan.hateblo.jp
目次
前回は、base64でバックエンドに画像を送信したが、次のエラーが表示れている。
XMLHttpRequest cannot load https://192.168.0.100:12345/hoge_image_processing. No ´Access―Control―Allow―Origin’ header is present on the requested resource. Origin 'https://192.168.0.100:12345' is therefore not allowed access.
結局は、バックエンドが返信してくるパケットのreplay headerに「Access―Control―Allow―Origin」がないというエラー。
対策
Decoratorを使うと簡単にheaderに´Access―Control―Allow―Origin’と設定できる。
参考資料のコードを参考にすると動く。
(私の環境ではうまく動かない関数があったりしたので、片っ端から修正)
@crossdomainの使い方は下記の通り。
... @app.route('/hoge_image_processing', methods=['POST']) @crossdomain(origin='*') def image_processing(): ...
これで簡単にヘッダーに必要情報が付加でき、エラーも解消された。
次回は、画像処理結果を通知するために使用する、flask->javascriptへのjsonデータ返信について纏める。