背景

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

需求分析

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

  1. 先实现将摄像头的画面实时展示在页面视频采集区域中;

  2. 将摄像头中的视频画面采集一帧成图片并回显;

  3. 将生成的图片上传至CDN拿到图片链接;

  4. 将图片链接上传到后端接口做处理;

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

实现

视频采集

由于 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 = falsevar 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在智能验机应用中的实践方案,敬请期待~

想了解更多转转公司的业务实践,点击关注下方的公众号吧!

Electron应用中实现调用外接摄像头并拍照上传相关推荐

  1. 在网页中调用摄像头实现拍照上传 - 高拍仪二次开发

    在网页中调用摄像头实现拍照上传 高拍仪二次开发     在一些公共部门的办事处,比如银行.护照办理中心.税务等,我们可能会注意到办公桌上摆着这样一台机器.办公人员用它拍摄各种证件.文件.表格,有时候还 ...

  2. c++ 二次开发 良田高拍仪_在网页中调用摄像头实现拍照上传 - 高拍仪二次开发...

    来源于  https://blog.csdn.net/weixin_40659738/article/details/78252562 在网页中调用摄像头实现拍照上传 高拍仪二次开发 在一些公共部门的 ...

  3. IE与非IE浏览器调用PC摄像头拍摄并且上传

     需要下载源码以及相关文件的可以到(不好意思,之前上传的不知道怎么回事就没了) http://download.csdn.net/detail/u013946285/9886280 中下载 一,f ...

  4. chrome摄像头java_Chrome 谷歌浏览器调用摄像头并拍照上传 java示例

    html页面: html5调用摄像头实现拍照 拍照 var video=document.getElementById("video"); var context=canvas.g ...

  5. pandorabox php,Openwrt Pandorabox 挂载摄像头 定时拍照上传百度网盘,实现实时监控(优酷路由宝)...

    事情是这样的:三四年前为了实现一个200米左右的组网,到anywlan 恩山 Openwrt论坛等等学习了各种路由器固件,期间玩过基于Openwrt的wifi小车. 玩过一些路由器  DB120 网件 ...

  6. h5 调用ios原生相机拍照上传照片

    1.html中的点击按钮和回调显示标签---------------直接上代码 <!DOCTYPE html> <html lang="en"> <h ...

  7. H5调用手机摄像头,实时拍照上传(旧)

    H5调用手机摄像头,完成拍照,实时上传(旧) 项目开发中,偶尔会遇到网页中调用手机摄像头,通过相册选择或直接实时拍照的方式,完成图片上传的功能型需求. 今天,就通过一个小的案例,演示一下完整的实现流程 ...

  8. vue调用本地摄像头实现拍照

    前言: vue调用本地摄像头实现拍照功能,由于调用摄像头有使用权限,只能在本地运行,线上需用https域名才可以使用. 实现效果: 1.摄像头效果: 2.拍照效果: 实现代码: <templat ...

  9. js调用pc摄像头实现拍照、录视频等,新版Chrome无访问http页面无法打开麦克风、摄像头

    js调用pc摄像头实现拍照.录视频等,新版Chrome无访问http页面无法打开麦克风.摄像头 新版Chrome配置 vue环境下的前端 function部分 ##由于没有https环境,只有http ...

最新文章

  1. Scene Player初始版本完成
  2. bat自动输入密码登录_如何制作自动设置计算机管理员密码的脚本
  3. vux Cell组件
  4. Java HashSet的实现原理详解
  5. 为什么总是封板又打开涨停_警惕!如果股票涨停板反复打开说明了什么?
  6. 360智能工程中心期待你的加入
  7. Java笔记3:Eclipse添加jar包
  8. Dialog高仿Toast实现
  9. matlab无穷积分求解_matlab编程求无穷限定积分
  10. [GZOI2019GXOI2019]省选AFO记
  11. 加贺电子发表手掌大小的小型轻量DLP放映机
  12. c语言中的结构体定义和常见用法
  13. 手机上那些排版优雅的文章是怎么实现的?
  14. 关于小程序widthFix图片高度不能自适应的问题
  15. 如何在PPT中插入LaTeX公式
  16. 自然语言中corpora.Dictionary的理解
  17. 钜大锂电池并联串联知识详解 并联串联注意事项18650
  18. “资产证券化支持实体经济万里行”启幕 探索实体经济发展新态势
  19. 数智化重塑冷链物流行业,SaaS云系统开发方案赋能冷链企业实现高效运营
  20. php中获取金钱,PHP处理金钱和金钱价值观

热门文章

  1. sqlcommand连接并更新SQLServer数据库小实例
  2. 开始翻译Fielding的博士论文
  3. 医院住院收费管理系统源码 HIS源码 医院系统源码
  4. 《Foundations of Cryptography》chapter 1 Introduction
  5. 山东科技大学OJ题库 1014-自动拨出电话的程序
  6. wacom android 文件传输,Wacom sign pro PDF
  7. 【Excel VBA】批量拆分工作表为独立文件批量复制文件内容到总文件的工作表
  8. 北京协和医学院823计算机原理,2017年北京协和医学院基础医学院823计算机原理考研导师圈点必考题汇编...
  9. 你相信贷款200万30年买房会让银行从你身上获益近500万吗?
  10. Linux终端运行fasterrcnn,运行tensorflow版的fasterRCNN遇到的问题总结