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在智能验机应用中的实践方案,更多关于Electron调用摄像头拍照上传的资料请关注我们其它相关文章!

(0)

相关推荐

  • electron打包中的巨坑解决记录

    目录 吐槽 问题一:css文件中图片加载失败 问题描述 解决过程 补充 问题二:无法使用cookie 问题描述 原因分析 总结 吐槽 从上周五到今天,我被electron打包折磨得死去活来,本来想让测试用桌面端的,现在不得不改用web端,真的好无语.今天解决问题顺利打包后来记录一下这个问题. 问题一:css文件中图片加载失败 问题描述 问题是这样的,electron打包为桌面端以后,登录页的表单是正常显示的,但是整个页面的背景图没了.我百度了一下,发现大多是说白屏啥的,但是我不是白屏啊,我的表单

  • Electron 剪贴板实现示例详解

    目录 正文 availableFormats readText 和 writeText readHTML 和 writeHTML readImage 和 writeImage readRTF 和 writeRTF clear 正文 在浏览器中可以通过 JavaScript 脚本来读写剪贴板数据,常用的是 document.execCommand 方法: // 复制数据 const inputElement = document.querySelector('#input') inputEleme

  • electron 中 webview的使用示例解析

    目录 正文 获取webview的dom webview 页面 webview页面的代码 新建public/preload.js文件 监听页面对否显示 禁止打开新窗口 刷新页面 上一页 下一页 正文 webview 想必都有所了解,比如:微信小程序嵌套H5 那么我们在electron中怎么使用webview呢? 我们先跟着官方文档展示一下,看是否能有效果: 若要在应用程序中嵌入网页, 请将 webview 标签添加到应用程序的被嵌入页面中 (这是将显示外来内容的应用程序页). 在最简单的例子中,

  • 一文详解Electron 电源状态管理

    目录 Electron 电源相关模块 其中 powerMonitor 模块提供的接口 powerSaveBlocker 模块提供的方法 空闲状态监控 电源状态监控 锁屏和解锁 休眠和唤醒 系统行为阻断 Electron 电源相关模块 在 Electron 中有两个模块是跟电源相关的: powerMonitor:用于获取电源相关信息,监听电源相关事件 powerSaveBlocker:用于阻止系统进入睡眠状态 其中 powerMonitor 模块提供的接口 powerSaveBlocker 模块提

  • electron渲染进程主进程相互传值示例解析

    目录 在electron中分为渲染进程和主进程 浏览器传值给主进程 浏览器环境 主进程 主进程传值给渲染进程 主进程 渲染进程 注意 在electron中分为渲染进程和主进程 渲染进程就是浏览器环境,主进程就是node环境 既然他们是不同的环境,那么为我们怎么让他们相互关联起来呢?或者说怎么传递值? 毕竟在开发中可能会遇到我想要的值只能在node环境中才能获取,然后node中可能也会需要浏览器环境的值:这个时候就需要两个环境联通起来相互传值 浏览器传值给主进程 浏览器环境 引入: import

  • Electron 网络拦截实战示例详解

    目录 正文 自定义 UA 绕过跨域限制 请求转发 正文 Electron 提供的 webRequest API,允许开发者对网络进行过滤和监听,并且可以修改 header 字段甚至请求地址,功能非常强大,它的类结构如下: 不过需要注意,该模块只能在主进程中使用,接下来为大家介绍 webRequest 三个非常典型的使用场景: 自定义 UA 有些接口为了过滤非法请求,会首先校验 UserAgent,正常的浏览器是无法伪造 UA 的,不过在 Electron 里面可以很容易做到,webRequest

  • Electron调用外接摄像头并拍照上传实现详解

    目录 背景 需求分析 实现 视频采集 MediaDevices.getUserMedia() 拍照生成图片 上传图片至CDN 1. 使用HTMLCanvasElement.toBlob() 语法 参数 2. 使用HTMLCanvasElement.toDataURL() 语法 参数 返回值 总结 背景 基于Electron实现的pc端智能验机应用,近期迭代了一个新的功能,需求是通过电脑外接摄像头对手机屏幕进行拍照,拍照后需将照片上传至服务端进行屏幕信息比对,确定被检测屏幕是否为原厂屏. 需求分析

  • 基于Struts文件上传(FormFile)详解

    Struts中FormFile用于文件进行上传 1.在jsp文件中进行定义 <form action="/StrutsFileUpAndDown/register.do" method="post" enctype="multipart/form-data"> 名字:<input type="text" name="name" /> 头像:<input type="f

  • python中Django文件上传方法详解

    Django上传文件最简单最官方的方法 1.配置media路径 在settings.py中添加如下代码: MEDIA_ROOT = os.path.join(BASE_DIR, 'media') 2.定义数据表 import os from django.db import models from django.utils.timezone import now as timezone_now def upload_to(instance, filename):     now = timezo

  • JavaScript 使用Ckeditor+Ckfinder文件上传案例详解

    目录 一.准备工作 二.解压 三.开始集成 一.准备工作 Ckeditor_4.5.7_full + Ckfinder_java_2.6.0 二.解压 1.解压ckeditor,和平常文件解压相同,正常解压即可 2.解压ckfinder,解压完成后进入ckfinder文件夹下,发现有CKFinderJava-2.6.0.war文件,继续解压. 3.注意看红框部分 三.开始集成 1.准备工作完成,将图1中的ckeditor,及图3中的ckfinder文件夹拷贝到我们自己的项目的WebContent

  • Docker创建自己的镜像与上传流程详解

    目录 引入 了解Docker的资源隔离和主机模式 创建 centos7 容器 部署mysql5.7 创建Docker Hub仓库 生成镜像 提交镜像 引入 在部署毕节服务器时遇到了个问题:   因为在三台服务器做好ovirt-engine超融合后,在主节点服务器上部署可视化平台需要安装mysql5.7,但是安装mysql时需要卸载一些依赖,但是由于怕影响原有的postgresql数据库和ovirt-engine的服务组件,选择了用docker容器部署mysql数据库.   在顺利创建好容器,配置

  • jQuery+php实现ajax文件即时上传的详解

    很多项目中需要用到即时上传功能,比如,选择本地图片后,立即上传并显示图像.本文结合实例讲解如何使用jQuery和PHP实现Ajax即时上传文件的功能,用户只需选择本地图片确定后即实现上传,并显示上传进度条,上传完成后,显示图片信息. HTML本示例基于jQuery以及相当出色的jquery.form插件,所以,先要载入jquery库和form插件.<script type="text/javascript" src="jquery.min.js"><

  • PHP文件上传实例详解!!!

    首先来看下上传部分的表单代码:   复制代码 代码如下: <form method="post" action="upload.php" enctype="multipart/form-data">        <table border=0 cellspacing=0 cellpadding=0 align=center width="100%">         <tr>       

  • php版阿里云OSS图片上传类详解

    本文实例讲述了php版阿里云OSS图片上传类.分享给大家供大家参考,具体如下: 1.阿里云基本函数 /** * 把本地变量的内容到文件 * 简单上传,上传指定变量的内存值作为object的内容 */ public function putObject($imgPath,$object) { $content = file_get_contents($imgPath); // 把当前文件的内容获取到传入文件中 $options = array(); try { $this->ossClient->

  • jquery组件WebUploader文件上传用法详解

    WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件,下文来为各位演示一下关于jquery WebUploader文件上传组件的用法. 使用WebUploader还可以批量上传文件.支持缩略图等等众多参数选项可设置,以及多个事件方法可调用,你可以随心所欲的定制你要的上传组件. 接下来我以图片上传实例,给大家讲解如何使用WebUploader. HTML 我们首先将css和相关js文件加载. <link rel="s

  • django mysql数据库及图片上传接口详解

    前言 我们在 django-rest-framework解析请求参数 文章中完成了接口文档到参数解析, 一个完整的流程中还缺少对数据库的操作. 本篇内容为django连接数据库, 并编写一个image表用来存储图片路径, 编写图片上传接口和查看数据库中所有图片路径的接口. 前期准备 django操作图片需要安装一个三方库叫做,Pillow workon python35 pip install pillow pip install pymysql Pillow这个库可以对图片进行操作, 例如生成

随机推荐