Electron如何调用摄像头并完成采集上传

Admin 2023-04-01 群英技术资讯 1030 次浏览

这篇文章给大家介绍了“Electron如何调用摄像头并完成采集上传”的相关知识,讲解详细,步骤过程清晰,有一定的借鉴学习价值,因此分享给大家做个参考,感兴趣的朋友接下来一起跟随小编看看吧。

目录
  • 背景
  • 需求分析
  • 实现
    • 视频采集
    • MediaDevices.getUserMedia()
    • 拍照生成图片
  • 上传图片至CDN
    • 1. 使用HTMLCanvasElement.toBlob()
    • 语法
    • 参数
    • 2. 使用HTMLCanvasElement.toDataURL()
      • 语法
      • 参数
      • 返回值
  • 总结

    背景

    基于Electron实现的pc端智能验机应用,近期迭代了一个新的功能,需求是通过电脑外接摄像头对手机屏幕进行拍照,拍照后需将照片上传至服务端进行屏幕信息比对,确定被检测屏幕是否为原厂屏。

    需求分析

    根据上面的需求,分析大概要以下几个步骤。

    • 先实现将摄像头的画面实时展示在页面视频采集区域中;
    • 将摄像头中的视频画面采集一帧成图片并回显;
    • 将生成的图片上传至CDN拿到图片链接;
    • 将图片链接上传到后端接口 做处理;

    确定了需要以上四个步骤后,接下来一步一步实现。

    实现

    视频采集

    由于 Electron 内置了 Chromium 浏览器,该浏览器对各项前端标准都支持得非常好,所以基于 Electron 开发应用不会遇到浏览器兼容性问题。几乎可以在 Electron 中使用所有 HTML5CSS3ES6 标准中定义的 API

    所以基于WebRTC提供的API即可获取到摄像头的视频流。

    MediaDevices.getUserMedia()

    代码如下:

    methods: {
        getUserMedia() {
            /* 可同时开启video(摄像头)和audio(麦克风) 这里只请求摄像头,所以只设置video为true */
            navigator.mediaDevices.getUserMedia({ video: true })
                .then(function(stream) {
                  /* 使用这个 stream 传递到成功回调中 */
                  this.success(stream)
                })
                .catch(function(err) {
                  /* 处理 error 信息 */
                  this.error(error)
                });
        }
    }
    

    MediaDevices.getUserMedia() 会提示用户给予使用媒体输入的许可,媒体输入会产生一个MediaStream,里面包含了请求的媒体类型的轨道。此流可以包含一个视频轨道(来自硬件或者虚拟视频源,比如相机、视频采集设备和屏幕共享服务等等)、一个音频轨道(同样来自硬件或虚拟音频源,比如麦克风、A/D 转换器等等),也可能是其它轨道类型。

    它返回一个 Promise 对象,成功后会resolve回调一个 MediaStream 对象。若找不到满足请求参数的媒体类型,promisereject回调一个NotFoundError

    现在已经成功获取到视频流,接下来就是将视频流回显到页面。 这里使用video标签完成,代码如下:

    <template>
        <div class="video-page">
            <div class="video-content">
                <video ref="video" class="video-item"></video>
            </div>
        </div>
    </template>
    export default {
       methods: {
           getUserMedia() {
                /* 可同时开启video(摄像头)和audio(麦克风) 这里只请求摄像头,所以只设置video为true */
                navigator.mediaDevices.getUserMedia({ video: true })
                    .then(function(stream) {
                      /* 使用这个 stream 传递到成功回调中 */
                      this.success(stream)
                    })
                    .catch(function(err) {
                      /* 处理 error 信息 */
                      this.error(error)
                    });
            },
           success(stream) {
               console.log('成功', stream);
               /* 将stream 分配给video标签 */
               this.$refs.video.srcObject = stream;
               this.$refs.video.play();
            }
        }
    }
    

    这时,摄像头中的画面就可以显示在页面video标签内,如下图。

    为了用户体验,在进入页面之前添加了判断摄像头是否已经接入并可用的逻辑,避免用户的摄像头未接入或者启动,造成应用不可用的错觉。

    使用MediaDevices.enumerateDevices()来获取可用媒体输入和输出设备的列表,例如摄像头、麦克风、耳机等。

    navigator.mediaDevices.enumerateDevices().then(devicesList => {
        console.log('------devicesList', deviceList)
    })
    

    得到的设备列表数据格式如下:

    kind类型有三种,分别是audioinputaudiooutputvideoinput。分别代表音视频的输入和输出。可在列表中查找目标媒体是否已经接入且可用。

    若有选择切换设备需求,可根据kind类型进行媒体设备分类,选择目标deviceId,传入navigator.mediaDevices.getUserMedia,完成来源切换。

     navigator.mediaDevices.getUserMedia({ video: { deviceId: xxxx } })
    

    拍照生成图片

    拍照其实就是截取视频中的某一帧,这里使用canvas来实现截取。getContext() 方法可返回一个对象,该对象提供了用于在画布上绘图的方法和属性。其中drawImage()方法用来向画布上绘制图像、画布或视频。

    <template>
        <div class="video-page">
            <div class="video-content">
                <video ref="video" class="video-item" v-if="showVideo"></video>
                <canvas ref="canvas" v-else width="500" height="346"></canvas>
            <div class="video-buttons">
                <div @click="capture" class="button-item capture">拍照</div>
                <div @click="submit" class="button-item submit"}">提交</div>
            </div>
        </div>
    </template>
    export default {
       data: {
           showVideo: true, // 是否展示摄像头画面
       },
       methods: {
            /* 拍照按钮点击 */
            capture() {
              this.showVideo = false
              var context = this.$refs.canvas.getContext('2d');
              /* 要跟video的宽高一致 */
              context.drawImage(this.$refs.video, 0, 0, 1000, 692, 0, 0, 500, 346);
            }
        }
    }
    

    拍照的图片回显至canvas标签。

    上传图片至CDN

    上个步骤已经完成了拍照,接下来就需要将图片上传至CDN,拿到图片链接。 这里有两种方式可以实现获取图片数据。

    1. 使用HTMLCanvasElement.toBlob()

    HTMLCanvasElement.toBlob() 方法生成 Blob 对象,用以展示 canvas 上的图片。因为直接可以拿到图片文件,所以无需再使用方法2中的函数来转化base64,直接可以获取到图片文件用来上传。

    语法

    toBlob(callback, type, quality)
    

    参数

    callback:回调函数,参数为Blob对象(目标图片文件)。

    type:图片格式,默认为image/png 可选

    quality:0-1的数字,表示图片质量,可选

    点击提交按钮按钮时,先获取图片文件,为上传做准备。

    methods: {
        /* 提交按钮点击 */
        submit() {
            const base64Url = this.$refs.canvas.toBlob(blob => {
                console.log('===blob', blob)
                const data = new FormData()
                data.append('file', blob)
                request.post('https://XXXXX/upload', data)
            }, "image/jpeg", 0.95)
        }
    }
    

    console的结果如下图:

    2. 使用HTMLCanvasElement.toDataURL()

    HTMLCanvasElement.toDataURL()方法返回一个包含图片展示的Data URL。

    Data URL,即前缀为 data: 协议的 URL,其允许内容创建者向文档中嵌入小文件。

    语法

    canvas.toDataURL(type, encoderOptions);
    

    参数

    type 图片格式,默认为image/png

    encoderOptions 0到1之间的值,用来选定图片质量,默认值是0.92,超出范围会使用默认值。

    返回值

    base64组成的图片源数据,上传前需转为图片文件。这里封装了一个convertBase64UrlToImgFile函数用来转换。代码如下:

    <template>
        <div class="video-page">
            <div class="video-content">
                <video ref="video" class="video-item" v-if="showVideo"></video>
                <canvas ref="canvas" v-else width="500" height="346"></canvas>
            <div class="video-buttons">
                <div @click="capture" class="button-item capture">拍照</div>
                <div @click="submit" class="button-item submit">提交</div>
            </div>
        </div>
    </template>
    export default {
       data: {
           /* 是否展示摄像头画面 */
           showVideo: true,
       },
       methods: {
            /* 将base64转为图片文件 */
            convertBase64UrlToImgFile(urlData, fileType) {
                const imgData = urlData.split('base64,').splice(-1)[0]
                /* 解码使用 base-64 编码的字符串 转换为byte */
                const bytes = window.atob(imgData)
                /* 处理异常,将ASCII码小于0的转换为大于0 */
                const ab = new ArrayBuffer(bytes.length)
                const ia = new Int8Array(ab)
                for (let i = 0; i < bytes.length; i++) {
                    ia[i] = bytes.charCodeAt(i)
                }
                /* 转换成文件,可以添加文件的type,lastModifiedDate属性 */
                const blob = new Blob([ab], { type: fileType })
                blob.lastModifiedDate = new Date()
                return blob
            },
            /* 提交按钮点击 */
            async submit() {
                const base64Url = this.$refs.canvas.toDataURL()
                const imgFile = this.convertBase64UrlToImgFile(base64Url, 'image/jpg')
                console.log('====imgFile', imgFile)
                const data = new FormData()
                data.append('file', imgFile)
                /* 上传 */
                request.post('https://XXXXX/upload', data)
            },
        }
    }
    

    convertBase64UrlToImgFile可用于在使用canvas外的场景进行base64转换图片文件。和HTMLCanvasElement.toBlob()方法得到的结果一致。

    以上两种方法都可以完成图片上传,最终拿到CDN图片链接后可传给后端进行处理。获取屏幕信息。

    总结

    通过以上四个步骤就完成了Electron应用中通过外接摄像头拍照并上传的功能。这里基本用不到Electron的能力,和在web端的实现方式并无区别,Electron在这里起到的作用就是获取摄像头媒体流不需要获取用户权限。

    Electron是基于ChromiumNode.js实现的,这就使前端开发者可以使用JavaScriptHTMLCSS轻松构建跨平台的桌面应用。Electron可以使用几乎所有的Web前端生态领域及Node.js生态领域的组件和技术方案。


    以上就是关于“Electron如何调用摄像头并完成采集上传”的相关知识,感谢各位的阅读,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注群英网络,小编每天都会为大家更新不同的知识。
    群英智防CDN,智能加速解决方案

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。

    猜你喜欢

    成为群英会员,开启智能安全云计算之旅

    立即注册
    专业资深工程师驻守
    7X24小时快速响应
    一站式无忧技术支持
    免费备案服务
    免费拨打  400-678-4567
    免费拨打  400-678-4567 免费拨打 400-678-4567 或 0668-2555555
    在线客服
    微信公众号
    返回顶部
    返回顶部 返回顶部
    在线客服
    在线客服