zoukankan      html  css  js  c++  java
  • JS打开摄像头并截图上传

    直入正题,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
  • 相关阅读:
    多线程程序设计学习(10)Future pattern
    Stack编程队列
    JS操作JSON总结
    java并发之TimeUnit理解
    java并发之DelayQueue实际运用示例
    netty的编解码器理解(转)
    spring中@Resource和@Autowired理解
    Netty中解码基于分隔符的协议和基于长度的协议
    构建基于Netty 的HTTP/HTTPS 应用程序
    对于spring中事务@Transactional注解的理解
  • 原文地址:https://www.cnblogs.com/imwtr/p/6413595.html
Copyright © 2011-2022 走看看