直入正題,JS打開攝像頭並截圖上傳至後端的一個完整步驟 1. 打開攝像頭主要用到getUserMedia方法,然後將獲取到的媒體流置入video標簽 2. 截取圖片主要用到canvas繪圖,使用drawImage方法將video的內容繪至canvas中 3. 將截取的內容上傳至伺服器,將canvas ...
直入正題,JS打開攝像頭並截圖上傳至後端的一個完整步驟
1. 打開攝像頭主要用到getUserMedia方法,然後將獲取到的媒體流置入video標簽
2. 截取圖片主要用到canvas繪圖,使用drawImage方法將video的內容繪至canvas中
3. 將截取的內容上傳至伺服器,將canvas中的內容轉為base64格式上傳,後端(PHP)通過file_put_contents將其轉為圖片
要註意的是,在chrome以外的瀏覽器中,使用攝像頭或多或少會出現一些問題,可能也是老問題了,所以以下代碼主要基於chrome使用
比如在最新版FireFox中的報錯,不知為啥
1. 打開攝像頭
getUserMedia 有新版本和舊版本兩種,建議使用新版本
舊版本位於navigator 對象下,根據瀏覽器不同有所不同
// 獲取媒體方法(舊方法) navigator.getMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMeddia || navigator.msGetUserMedia;
if (navigator.getMedia) { navigator.getMedia({ video: true }, function(stream) { mediaStreamTrack = stream.getTracks()[0]; video.src = (window.URL || window.webkitURL).createObjectURL(stream); video.play(); }, function(err) { console.log(err); }); }
第一個參數中指示需要使用視頻(video)或音頻(audio),更多參見文檔
第二個參數中指示調用成功後的回調,其中帶一個參數(MediaStream),在舊版本中可以直接通過調用MediaStream.stop() 來關閉攝像頭,不過在新版之中已廢棄。需要使用MediaStream.getTracks()[index].stop() 來關閉相應的Track
第三個參數指示調用失敗後的回調
新版本位於navigator.mediaDevices 對象下
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then(function(stream) { console.log(stream); mediaStreamTrack = typeof stream.stop === 'function' ? stream : stream.getTracks()[1]; video.src = (window.URL || window.webkitURL).createObjectURL(stream); video.play(); }).catch(function(err) { console.log(err); }) }
與舊版類似,不過該方法返回了一個Promise對象,可以使用then和catch表示成功與失敗的回調
需要註意的是,MediaStream.getTracks() 返回的Tracks數組是按第一個參數倒序排列的
比如現在定義了
{ video: true, audio: true }
想關閉攝像頭,就需要調用MediaStream.getTracks()[1].stop();
同理,0對應於audio的track
使用createObjectURL 將MediaStream寫入video標簽,就能夠存儲實時的媒體流數據(也可以方便的實時查看畫面)
舊版本中webkitURL 對象以不被支持,需要使用URL對象
<video width="200" height="150"></video> <canvas width="200" height="150"></canvas> <p> <button id="snap">截取圖像</button> <button id="close">關閉攝像頭</button> <button id="upload">上傳圖像</button> </p> <img id="uploaded" width="200" height="150" />
2. 截取圖像
將內容寫入即可
// 截取圖像 snap.addEventListener('click', function() { context.drawImage(video, 0, 0, 200, 150); }, false);
3. 關閉攝像頭
// 關閉攝像頭 close.addEventListener('click', function() { mediaStreamTrack && mediaStreamTrack.stop(); }, false);
4. 上傳截取的圖像
canvas.toDataURL('image/png')
// 上傳截取的圖像 upload.addEventListener('click', function() { jQuery.post('/uploadSnap.php', { snapData: canvas.toDataURL('image/png') }).done(function(rs) { rs = JSON.parse(rs); console.log(rs); uploaded.src = rs.path; }).fail(function(err) { console.log(err); }); }, false);
而這裡的後端(PHP)則將獲取的內容轉換成圖像文件保存
需要註意的是,要將base64的頭部信息欄位去掉再保存,否則似乎圖像是損壞無法打開滴
<?php $snapData = $_POST['snapData']; $snapData = str_replace('data:image/png;base64,', '', $snapData); // $snapData = str_replace(' ', '+', $snapData); $img = base64_decode($snapData); $uploadDir = 'upload/'; $fileName = date('YmdHis', time()) . uniqid(); if (!(file_put_contents($uploadDir . $fileName, $img))) { echo json_encode(array('code' => 500, 'msg' => '文件上傳失敗')); } else { echo json_encode(array('code' => 200, 'msg' => '文件上傳成功', 'path' => $uploadDir . $fileName)); } ?>
完整JS代碼
1 <script type="text/javascript" src="jquery.js"></script> 2 <script type="text/javascript"> 3 function $(elem) { 4 return document.querySelector(elem); 5 } 6 7 // 獲取媒體方法(舊方法) 8 navigator.getMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMeddia || navigator.msGetUserMedia; 9 10 var canvas = $('canvas'), 11 context = canvas.getContext('2d'), 12 video = $('video'), 13 snap = $('#snap'), 14 close = $('#close'), 15 upload = $('#upload'), 16 uploaded = $('#uploaded'), 17 mediaStreamTrack; 18 19 // 獲取媒體方法(新方法) 20 // 使用新方法打開攝像頭 21 if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { 22 navigator.mediaDevices.getUserMedia({ 23 video: true, 24 audio: true 25 }).then(function(stream) { 26 console.log(stream); 27 28 mediaStreamTrack = typeof stream.stop === 'function' ? stream : stream.getTracks()[1]; 29 30 video.src = (window.URL || window.webkitURL).createObjectURL(stream); 31 video.play(); 32 }).catch(function(err) { 33 console.log(err); 34 }) 35 } 36 // 使用舊方法打開攝像頭 37 else if (navigator.getMedia) { 38 navigator.getMedia({ 39 video: true 40 }, function(stream) { 41 mediaStreamTrack = stream.getTracks()[0]; 42 43 video.src = (window.URL || window.webkitURL).createObjectURL(stream); 44 video.play(); 45 }, function(err) { 46 console.log(err); 47 }); 48 } 49 50 // 截取圖像 51 snap.addEventListener('click', function() { 52 context.drawImage(video, 0, 0, 200, 150); 53 }, false); 54 55 // 關閉攝像頭 56 close.addEventListener('click', function() { 57 mediaStreamTrack && mediaStreamTrack.stop(); 58 }, false); 59 60 // 上傳截取的圖像 61 upload.addEventListener('click', function() { 62 jQuery.post('/uploadSnap.php', { 63 snapData: canvas.toDataURL('image/png') 64 }).done(function(rs) { 65 rs = JSON.parse(rs); 66 67 console.log(rs); 68 69 uploaded.src = rs.path; 70 }).fail(function(err) { 71 console.log(err); 72 }); 73 }, false); 74 75 </script>View Code