HTML5,JavaScript 和现代浏览器这套三驾马车的组合,使得传统的 Web 应用较之过去能实现更多更丰富的同用户交互的功能。摄像头如今已成为智能手机的标配,前端 Web 应用也出现了越来越多的打开本机摄像头,扫描条形码,二维码等需求。
本文介绍两种通过 JavaScript 实现在浏览器环境里调用设备摄像头的开发技术。
方法1:基于现代浏览器支持的 WebRTC API 实现
我采用该思路实现了一个简单的 Web 页面,全部源代码维护在如下的 Github 代码仓库里:
https://github.com/wangzixi-d...
首先看看运行该 Web 应用的效果。
通过笔记本电脑访问,浏览器会弹出窗口询问用户是否允许该应用访问设备上的摄像头:
点击允许之后,应用下方区域就会实时显示我的摄像头正对着的区域的图像:
点击“拍照”按钮后,摄像头显示的图像就会被固化在该按钮下方,并且以图片的方式自动保存到本地。
在我的三星手机上访问该链接,首先一样要授权该应用使用摄像头:
对准我电脑面前一个异形手办进行拍照:
自动生成一张图片并保存到手机上:
几个关键的实现点说明:
(1) JavaScript 之所以通过浏览器能够识别到设备可用摄像头(包括可用的音频输入和输出设备),是因为现代浏览器支持的一组名为 WebRTC(Web Real Time Communication,网页即时通信)的 API. 这个 API 能帮助 Web 应用开发人员通过简单的 JavaScript 编程就能实现功能丰富的实时多媒体应用,而无需学习多媒体的数字信号处理知识。Web 应用的使用者也无需下载额外的插件。
用 JavaScript 进行设备可用多媒体设备的检测,核心代码如下:
navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(handleError);
这句代码前半段 navigator.mediaDevices.enumerateDevices() 是浏览器支持的原生 API,这是一个异步调用,返回一个 promise 对象:
等到该异步调用的结果可供应用程序使用之后,我们通过链式调用 then 传入的回调函数 gotDevices 被触发,输入的参数就是 navigator.mediaDevices.enumerateDevices() 调用的返回值。在调试器里看看这个返回值的明细:
从调试器里得知 enumerateDevices 这个函数返回了我笔记本电脑上一系列可用的音视频设备,这些信息和我通过操作系统里看到的设备信息一致:
(2) 我的 html 页面里定义了一个 HTML5 原生支持的 video 标签, 用于显示通过设备摄像头观察到的图像。
但是我们还需要把设备摄像头同这个 video 标签关联起来。方式是给这个标签的 dom 对象的srcObject 属性赋一个 MediaStream (媒体数据流)对象。
这个 MediaStream 对象从哪里来?同理,通过链式调用navigator.mediaDevices.getUserMedia(constraints) 得到:
(3) 点击拍照按钮后,自动生成图片并下载到本地的功能在按钮的 click 事件响应函数里实现。首先调用 canvas 标签对应 Context 的 API drawImage 将显示摄像头内容的 video 标签当前显示的内容绘制到 canvas 标签页上,然后用此内容生成格式为 jpeg 的图片,下载到本地。
方法2:使用 SAP UI5 自定义控件
这种方式本质上同方法一异曲同工,只不是封装性更好,将方法1 描述的步骤,封装成一个 SAP UI5 可重用控件,方便使用 SAP UI5 这个前端框架进行开发的前端程序员直接使用。
关于 SAP UI5 这个企业级前端开发框架的介绍,参考笔者之前的 InfoQ 文章:面向企业级前端应用的开发框架 UI5 的发展简史介绍。
先回忆方法1 技术实现的要点:
(1) 在 web 应用的 HTML 页面里定义 HTML5 用于显示视频的原生标签: video
(2) 使用 WebRTC 的 API,获取设备摄像头对应的 MediaStream 对象,再将这个对象实例赋给 video 标签对应的 DOM对象的 srcObject 属性.
以上两步实现之后,我们通过摄像头观察到的视频图像,就能实时显示在 web 应用的 video 标签里了。至于将某一时间点里 video 标签里显示的视频内容保存成图片并下载,其对应的 JavaScript 代码对于所有的前端框架并没有太大的不同,本文略过。
因此,使用 SAP UI5 开发,我们无非得重复以上两个步骤。
SAP UI5 应用最常用的视图格式为 XML 视图。我们直接在 XML 视图里加上 HTML 原生的 video 或者 div 标签,会发生什么?
404 错误,UI5 框架加载不了 div.js 这个脚本文件。
笔者以前还在 SAP 成都研究院 CRM Fiori 应用开发团队工作时,曾经写过一个 SAP UI5 框架代码的学习教程,里面有两篇文章,详细介绍了 SAP UI5 XML 视图运行时的渲染原理:
- Why my formatter does not work? A trouble shooting example to know how it works
- How I do self-study on a given Fiori control – part 10
简单地说,就是 SAP UI5 里有个 XMLTemplateProcessor.js 的实现,运行时当 XML 视图的源文件被浏览器加载解析成 DOM 后,它会对 DOM 树进行深度优先遍历,对遇到的每一个 UI5 标签,加载其实现文件(如果是在 UI5 调试模式下),然后创建这个标签对应的实例。
回到本文的例子,我写到 SAP UI5 XML 视图里的 div 标签被当成了一个 SAP UI5 XML 的控件,所以 UI5 框架自动去找这个根本不存在的 div 控件的实现文件,当然找不到了。
知道问题出在哪里,解决的思路自然就有了。自己把 HTML5 原生标签 video 封装成 UI5 控件不就行了?
SAP UI5 开源社区里已经有一个封装好的 library:
https://github.com/tiagobalme...
先看这个例子在笔记本电脑上访问的效果:
点击页面上显示的摄像头拍摄的内容,能自动保存成一张图片。
手机上的显示效果:
然后再来看这个 library
的实现原理。
这个 camera 自定义 UI5 控件实现的层级结果如下:
SAP UI5 自定义控件的实现包括三个 JavaScript 文件:
- library.js:定义这个控件抬头级别的控制信息,比如名称,版本号,依赖等。
- Camera.js:实现了将 WebRTC API 获得的 MediaStream 对象实例绑定到控件封装的 video 元素上的步骤。
- CameraRender.js:负责将这个自定义控件在XML视图里的标签
Camera
渲染成原生的video和canvas标签的组合。
SAP UI5 的每一个控件都有一个与之对应的渲染类,用于完成 XML 视图里 UI5 的标签到 HTML5 原生标签的转换:
如何使用这个自定义控件呢?
在 XML 视图里使用如下定义即可:
总结
本文介绍了基于 WebRTC 技术使用 JavaScript 调用本机摄像头的解决方案。WebRTC 可以为基于开放标准的应用程序添加实时通信功能,支持在对等点之间发送视频、语音和通用数据,允许开发人员构建强大的语音和视频通信解决方案。
WebRTC 可用于所有现代浏览器以及所有主流操作系统的本地客户端。WebRTC 背后的技术是作为一个开放的 Web 标准实现,并且可以在所有主流浏览器中作为常规 JavaScript API 使用。
本文两个例子在 Windows 10 操作系统的 Chrome 浏览器里实现并通过测试。对于原生客户端,如 Android 和 iOS 应用程序,可以使用提供相同功能的 WebRTC 库。
希望本文介绍的知识点对大家采取 JavaScript 实现浏览器环境里调用本机摄像头的需求能有所帮助,感谢阅读。