web端前端调取摄像头并实现拍照功能

2024-07-11 1386阅读

文章目录

    • 前言
    • window.navigator
    • navigator.mediaDevices
    • 获取摄像头
    • 截取当前画面(canvas)
    • 源码
    • 小结

      前言

      接到一个需求,设计整体实现pc端 OA系统上下班面部识别打卡的功能,智能识别面部肯定是后端进行对比是不是本人,前端需要实现拉取摄像头,进行拍照,并保存照片,传给后端,进行智能分析,返回参数
      

      window.navigator

      JavaScript Window Navigator是JavaScript中一个常用的浏览器对象模型,它提供了许多属性和方法,用于访问用户浏览器的信息。
      window.navigator 对象在编写时可不使用 window 这个前缀
      
      1. Navigator属性
         
        // appCodeName 该属性返回浏览器的代码名称。在大多数浏览器中,它的值都是“Mozilla”,因为它们使用了Mozilla浏览器的代码。 txt = "

        浏览器代号: " + navigator.appCodeName + "

        "; // 该属性返回浏览器的名称。它的值可能是"Microsoft Internet Explorer"、"Netscape"、"Chrome"等。 txt+= "

        浏览器名称: " + navigator.appName + "

        "; // 该属性返回浏览器的版本信息。 txt+= "

        浏览器版本: " + navigator.appVersion + "

        "; // language 属性返回浏览器语言: txt+= "

        浏览器语言: " + navigator.language + "

        "; // onLine 属性返回 true,假如浏览器在线: txt+= "

        浏览器是否在线: " + navigator.onLine + "

        "; // 该属性返回一个布尔值,表示浏览器是否启用cookie。 txt+= "

        启用Cookies: " + navigator.cookieEnabled + "

        "; // 该属性返回运行浏览器的操作系统平台,例如Windows、Mac OS X、Linux等。 txt+= "

        硬件平台: " + navigator.platform + "

        "; // 该属性返回包含浏览器版本和操作系统信息的用户代理字符串。 txt+= "

        用户代理: " + navigator.userAgent + "

        "; txt+= "

        用户代理语言: " + navigator.systemLanguage + "

        "; document.getElementById("example").innerHTML=txt;
        web端前端调取摄像头并实现拍照功能
      2. Navigator 对象方法

        javaEnabled返回一个布尔值,该值指示浏览器是否支持并启用了 Java。如果是,则返回 true,否则返回 false。

      3. 实际运用

        a)浏览器版本检测

        在开发网站时,我们需要确保网站能够在各种浏览器上正确地运行。由于不同的浏览器版本在处理JavaScript代码方面存在差异,因此我们需要能够检测浏览器版本并根据浏览器版本来编写JavaScript代码。可以使用Navigator对象中的属性来检测浏览器版本,例如 userAgent 属性和 appVersion 属性。

        if (navigator.userAgent.indexOf("MSIE") != -1) {
          // 如果是IE浏览器,执行相应的操作
        } else if (navigator.userAgent.indexOf("Firefox") != -1) {
          // 如果是Firefox浏览器,执行相应的操作
        } else if (navigator.userAgent.indexOf("Chrome") != -1) {
          // 如果是Chrome浏览器,执行相应的操作
        } else if (navigator.userAgent.indexOf("Opera") != -1) {
          // 如果是Opera浏览器,执行相应的操作
        } else if (navigator.userAgent.indexOf("Safari") != -1) {
          // 如果是Safari浏览器,执行相应的操作
        }
        
        b)浏览器版本检测

        在编写JavaScript代码时,我们可能需要使用一些浏览器特定的API。但是不同的浏览器支持的API可能不同,因此我们需要进行浏览器能力检测,以确保我们的代码能够在各种浏览器上正确地运行。可以使用Navigator对象中的属性来检测浏览器的能力,例如 cookieEnabled 属性和 geolocation 属性。

        if (navigator.cookieEnabled) {
          // 如果浏览器支持cookie,执行相应的操作
        }
         
        if ("geolocation" in navigator) {
          // 如果浏览器支持地理位置信息,执行相应的操作
        }
        
        c)获取浏览器位置信息

        Navigator对象中的geolocation属性可以获取用户的地理位置信息,这在实现一些地理位置相关的功能时非常有用。以下是一个获取用户位置信息的示例:

        // 注在谷歌浏览器会被拦截会报错延迟 index.html:42 Error code: 3; message: Timeout expired
        // 代码在edge浏览器中执行
        navigator.geolocation.getCurrentPosition(function(position) {
          var latitude = position.coords.latitude;
          var longitude = position.coords.longitude;
          // 根据经纬度显示用户当前位置
         console.log(latitude) // 39.135874
          console.log(longitude) // 117.18322
        }, 
        function(error) {
           console.error("Error code: " + error.code + "; message: " + error.message);
        },
         {
            timeout: 1000, // 超时时间为10秒
            maximumAge: 60000, // 最大缓存时间为1分钟
            enableHighAccuracy: true // 开启高精度模式
          });
        

      navigator.mediaDevices

      接口提供访问连接媒体输入的设备,如照相机和麦克风,以及屏幕共享等。它可以使你取得任何硬件资源的媒体数据。
      
      	let camera = window.navigator.mediaDevices;
      	console.log(camera, 'cameracameracameracamera');
      

      web端前端调取摄像头并实现拍照功能

      navigator.mediaDevices 详细的使用方法以及API可以去看官方文档

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

      获取摄像头

      navigator.mediaDevices.getUserMedia()官方文档

      1. 先判断当前浏览器是否有摄像设备并给与权限,我们先调取 enumerateDevices 函数来查看当前媒体设备是否存在。它的返回值是一个 promise 类型,我们直接用 async 和 await 来简化一下
        let camera = window.navigator.mediaDevices;
        let devices = await camera.enumerateDevices();
        console.log(devices, 'devices');
        
        web端前端调取摄像头并实现拍照功能

        从上图可以看出,我的电脑有6个音频设备和一个视频设备,那么我们就可以放下进行下一步了。

      2. 设置视频图像显示的位置
      3. 获取视频流并在相应的位置展示并播放
        let cameraMedia = window.navigator.mediaDevices;
          let devices = await cameraMedia.enumerateDevices();
          if (!!devices) {
            let camera = await cameraMedia.getUserMedia({
              audio: false, // 不需要音频
              video: {
                width: 300,
                height: 300,
                // facingMode: { exact: 'environment' },// 设置后置摄像头 pc端不需要设置
                // facingMode: { exact: 'uder' }, // 设置前置摄像头
              },
            });
            if (!videoEL.value) return;
            videoEL.value.srcObject = camera;
            videoEL.value.play();
          }	
        

      截取当前画面(canvas)

      1. 打开 Performance 标签卡,记录一下打开掘金首页的过程,可以看到浏览器的整个渲染过程其实也是一帧一帧拼接到一起,才完成了整个页面的渲染。

        web端前端调取摄像头并实现拍照功能

      2. 当我按下按钮的时候,想办法将 video 标签当前的画面保存下来。需要用canvas

      3. 首先创建一个空白的 canvas 元素,元素的宽高设置为和 video 标签一致。

      4. canvas 的 getContext 方法,接受一个字符串 “2d” 作为参数,它会把这个画布的上下文返回

        if (!videoEL.value || !wrapper.value) return;
          const canvas = document.createElement('canvas');
           canvas.width = videoEL.value.videoWidth;
           canvas.height = videoEL.value.videoHeight;
           //拿到 canvas 上下文对象
           const ctx = canvas.getContext('2d');
           ctx?.drawImage(videoEL.value, 0, 0, canvas.width, canvas.height);
           wrapper.value.appendChild(canvas); // 将 canvas 投到页面上
      

      web端前端调取摄像头并实现拍照功能

      源码

      项目是基于 Vue-Vben-Admin搭建的

        
          
      import { defineComponent, ref, unref } from 'vue'; import { BasicModal, useModalInner } from '/@/components/Modal'; import { BasicForm, useForm } from '/@/components/Form/index'; import { useI18n } from '/@/hooks/web/useI18n'; import { useMessage } from '/@/hooks/web/useMessage'; import { ActionEnum, VALIDATE_API } from '/@/enums/commonEnum'; export default defineComponent({ name: '编辑积分商品', components: { BasicModal, BasicForm }, emits: ['success', 'register'], setup(_, { emit }) { const { t } = useI18n(); const type = ref(ActionEnum.ADD); const { createMessage } = useMessage(); let videoEL = ref(); const wrapper = ref(); const [registerModel, { setModalProps: setProps, closeModal: close }] = useModalInner(async (data) => { setProps({ confirmLoading: false }); type.value = data?.type || ActionEnum.ADD; handleCamera(); }); async function handleCamera() { let cameraMedia = window.navigator.mediaDevices; let devices = await cameraMedia.enumerateDevices(); if (!!devices) { let camera = await cameraMedia.getUserMedia({ audio: false, // 不需要音频 video: { width: 300, height: 300, // facingMode: { exact: 'environment' },// 设置后置摄像头 pc端不需要设置 // facingMode: { exact: 'uder' }, // 设置前置摄像头 }, }); if (!videoEL.value) return; videoEL.value.srcObject = camera; videoEL.value.play(); } } async function handleSubmit() { try { if (!videoEL.value || !wrapper.value) return; const canvas = document.createElement('canvas'); canvas.width = videoEL.value.videoWidth; canvas.height = videoEL.value.videoHeight; //拿到 canvas 上下文对象 const ctx = canvas.getContext('2d'); ctx?.drawImage(videoEL.value, 0, 0, canvas.width, canvas.height); wrapper.value.appendChild(canvas); } finally { setProps({ confirmLoading: false }); } } return { type, videoEL, wrapper, t, registerModel, handleSubmit }; }, });

      小结

      实现拍照的整体思路其实很简单,仅仅需要了解到视频其实也是一帧一帧画面构成的,而 canvas 恰好有捕捉当前帧的能力。

VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]