zoukankan      html  css  js  c++  java
  • vue实现PC端调用摄像头拍照人脸录入、移动端调用手机前置摄像头人脸录入、及图片旋转矫正、压缩上传base64格式/文件格式

    关注公众号: 微信搜索 web全栈进阶 ; 收货更多的干货

    类似需求基本粘贴复制就能用

    1. PC端

    调用摄像头拍照上传base64格式到后台,这个没什么花里胡哨的骚操作,直接看代码 (canvas + video)

    <template>
        <div>
           <!--开启摄像头-->
            <img @click="callCamera" :src="headImgSrc" alt="摄像头">
            <!--canvas截取流-->
            <canvas ref="canvas" width="640" height="480"></canvas>
            <!--图片展示-->
            <video ref="video" width="640" height="480" autoplay></video>
            <!--确认-->
            <el-button size="mini" type="primary" @click="photograph"></el-button>
        </div>
    </template>   
    <script>
    export default {
      data () {
        return {
          headImgSrc: require('@/assets/image/photograph.png')
        }
      },
      methods: {
        // 调用摄像头
        callCamera () {
          // H5调用电脑摄像头API
          navigator.mediaDevices.getUserMedia({
            video: true
          }).then(success => {
            // 摄像头开启成功
            this.$refs['video'].srcObject = success
            // 实时拍照效果
            this.$refs['video'].play()
          }).catch(error => {
            console.error('摄像头开启失败,请检查摄像头是否可用!')
          })
        },
        // 拍照
        photograph () {
          let ctx = this.$refs['canvas'].getContext('2d')
          // 把当前视频帧内容渲染到canvas上
          ctx.drawImage(this.$refs['video'], 0, 0, 640, 480)
          // 转base64格式、图片格式转换、图片质量压缩
          let imgBase64 = this.$refs['canvas'].toDataURL('image/jpeg', 0.7)
          
        // 由字节转换为KB 判断大小
          let str = imgBase64.replace('data:image/jpeg;base64,', '')
          let strLength = str.length
          let fileLength = parseInt(strLength - (strLength / 8) * 2)
        // 图片尺寸  用于判断
          let size = (fileLength / 1024).toFixed(2)
          console.log(size)
    
         // 上传拍照信息  调用接口上传图片 .........
    
          // 保存到本地
          this.dialogCamera = false
          let ADOM = document.createElement('a')
          ADOM.href = this.headImgSrc
          ADOM.download = new Date().getTime() + '.jpeg'
          ADOM.click()
        },
        // 关闭摄像头
        closeCamera () {
          if (!this.$refs['video'].srcObject) {
            this.dialogCamera = false
            return
          }
          let stream = this.$refs['video'].srcObject
          let tracks = stream.getTracks()
          tracks.forEach(track => {
            track.stop()
          })
          this.$refs['video'].srcObject = null
        },
      }
    }
    </script>
    

    2. 移动端

    调用手机前置摄像头人脸录入、及图片旋转矫正、压缩上传base64格式/文件流格式;

    移动端幺蛾子就多了,比如部分手机打开的不是前置摄像头,部分手机拍照图片旋转了,高清手机拍的图片非常大........

    具体思路:

    1. 通过input 开启手机前置摄像头accept="image/*"为开启摄像头capture="user"为开启前置摄像头;微信公众号的话可以微信jssdk,但它不支持前置摄像头,默认后置)
    2. 通过 exif.js 判断旋转了多少度在通过canvas矫正
    3. 图片太大或超过规定尺寸则通过canvas压缩

    HTML 部分:

    <input ref="file" type="file" accept="image/*" capture="user">
    

    JS 部分: 接口使用的Vuex调用可忽略

    <script>
    export default {
      data () {
        return {}
      },
      methods: {
        // 压缩图片 and 旋转角度纠正
        compressImage (event) {
          let _this = this
          let file = event.target.files[0]
          let fileReader = new FileReader()
          let img = new Image()
          let imgWidth = ''
          let imgHeight = ''
          // 旋转角度
          let Orientation = null
          // 缩放图片需要的canvas
          let canvas = document.createElement('canvas')
          let ctx = canvas.getContext('2d') // 图片大小  大于2MB 则压缩
          const isLt2MB = file.size < 2097152
          // 通过 EXIF 获取旋转角度 1 为正常  3 为 180°  6 顺时针90°  9 为 逆时针90°
          EXIF.getData(file, function () {
            EXIF.getAllTags(this)
            Orientation = EXIF.getTag(this, 'Orientation')
          })
          // 文件读取 成功执行
          fileReader.onload = function (ev) {
            // 文件base64化,以便获知图片原始尺寸
            img.src = ev.target.result
          }
          // 读取文件
          fileReader.readAsDataURL(file)
          // base64地址图片加载完毕后
          img.onload = function () {
            imgWidth = img.width
            imgHeight = img.height
            canvas.width = img.width
            canvas.height = img.height
            // 目标尺寸
            let targetWidth = imgWidth
            let targetHeight = imgHeight
            // 不需要压缩 不需要做旋转处理
            if (isLt2MB && imgWidth < 960 && imgHeight < 960 && !Orientation) return _this.XMLHttpRequest(file)
            if (isLt2MB && imgWidth < 960 && imgHeight < 960 && +Orientation === 1) return _this.XMLHttpRequest(file)
            // 大于2MB 、img宽高 > 960 则进行压缩
            if (!isLt2MB || imgWidth >= 960 || imgHeight >= 960) {
              // 最大尺寸
              let maxWidth = 850
              let maxHeight = 850
              // 图片尺寸超过 960 X 960 的限制
              if (imgWidth > maxWidth || imgHeight > maxHeight) {
                if (imgWidth / imgHeight > maxWidth / maxHeight) {
                  // 更宽,按照宽度限定尺寸
                  targetWidth = maxWidth
                  targetHeight = Math.round(maxWidth * (imgHeight / imgWidth))
                } else {
                  targetHeight = maxHeight
                  targetWidth = Math.round(maxHeight * (imgWidth / imgHeight))
                }
              }
              // canvas对图片进行缩放
              canvas.width = targetWidth
              canvas.height = targetHeight
              // 图片大小超过 2Mb 但未旋转  则只需要进行图片压缩
              if (!Orientation || +Orientation === 1) {
                ctx.drawImage(img, 0, 0, targetWidth, targetHeight)
              }
            }
            // 拍照旋转 需矫正图片
            if (Orientation && +Orientation !== 1) {
              switch (+Orientation) {
                case 6:     // 旋转90度
                  canvas.width = targetHeight
                  canvas.height = targetWidth
                  ctx.rotate(Math.PI / 2)
                  // 图片渲染
                  ctx.drawImage(img, 0, -targetHeight, targetWidth, targetHeight)
                  break
                case 3:     // 旋转180度
                  ctx.rotate(Math.PI)
                  // 图片渲染
                  ctx.drawImage(img, -targetWidth, -targetHeight, targetWidth, targetHeight)
                  break
                case 8:     // 旋转-90度
                  canvas.width = targetHeight
                  canvas.height = targetWidth
                  ctx.rotate(3 * Math.PI / 2)
                  // 图片渲染
                  ctx.drawImage(img, -targetWidth, 0, targetWidth, targetHeight)
                  break
              }
            }
            // base64 格式   我这是vuex 形式 重点是 canvas.toDataURL('image/jpeg', 1)
            // _this.$store.commit('SAVE_FACE_IMAGE_BASE64', canvas.toDataURL('image/jpeg', 1))
         // 调用接口上传
            // _this.upAppUserFaceByBase64()
            // 通过文件流格式上传
         canvas.toBlob(function (blob) {
              _this.XMLHttpRequest(blob)
            }, 'image/jpeg', 1)
          }
        },
        // 上传base64方式
        upAppUserFaceByBase64 () {
          this.$store.dispatch('upAppUserFaceByBase64', {
            baseFace: this.$store.state.faceImageBase64
          }).then(res => {
          // 上传成功
          }).catch(err => {
            console.log(err)
          })
        },
        // 上传
        XMLHttpRequest (params) {
          // 图片ajax上传
        let action = '后台接口地址'
          let xhr = new XMLHttpRequest()
        let formData = new FormData()
          formData.delete('multipartFile')
          formData.append('multipartFile', params)
          // 文件上传成功回调
          xhr.onprogress = this.updateProgress
          xhr.onerror = this.updateError
          // 开始上传
          xhr.open('POST', action, true)
          xhr.send(formData)
        },
        // 上传成功回调
        updateProgress (res) {
          // res 就是成功后的返回 
        },
        // 上传失败回调
        updateError (error) {
          console.log(error)
        }
      }
    }
    </script>
    

    结尾

    无关紧要代码删的导致有点乱了,有不懂或疑问之处欢迎留言;

  • 相关阅读:
    多态
    163VIP邮箱哪个好?为什么要使用邮箱客户端?
    163邮箱的格式什么样的?常见的电子邮箱品牌有哪些?
    申请企业邮箱需要准备什么材料?外贸邮箱怎么注册?
    《10秒挑战》h5游戏案例分析
    H5反应类爆款游戏分享
    企业邮箱多少钱,哪家企业邮箱更具性价比?
    注册申请企业邮箱,哪家最优惠 #万元礼包来袭#
    购买一个163VIP邮箱,3位超短靓号更惊喜~
    小程序对H5游戏的技术分析
  • 原文地址:https://www.cnblogs.com/ljx20180807/p/10839713.html
Copyright © 2011-2022 走看看