前端调用电脑摄像头

项目中需要前端调用,所以做了如下操作
先看一下效果吧
主要是基于vue3,通过canvas把画面转成base64的形式,然后是把base64转成
file文件,最后调用了一下上传接口


以下是代码

进入页面先调用一下摄像头

javascript 复制代码
  navigator.mediaDevices
    .getUserMedia({ video: true })
    .then((stream) => {
      video.value.srcObject = stream
    })
    .catch((error) => {
      console.error(error)
    })
  state.photoUrl = ''
  state.photo = true

拍照

javascript 复制代码
const canvas = document.createElement('canvas')
  canvas.width = video.value.videoWidth
  canvas.height = video.value.videoHeight
  canvas.getContext('2d').drawImage(video.value, 0, 0, canvas.width, canvas.height)
  state.photoUrl = canvas.toDataURL('image/png')

转base64

javascript 复制代码
  let arr = dataurl.split(',')
  let mime = arr[0].match(/:(.*?);/)[1]
  let suffix = mime.split('/')[1]
  let bstr = atob(arr[1])
  let n = bstr.length
  let u8arr = new Uint8Array(n)
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
  }
  return new File([u8arr], `${filename}.${suffix}`, {
    type: mime,
  })

完整代码

javascript 复制代码
<template>
  <div>
    <div>
      <div>摄像头实时画面</div>
      <div class="hm">
        <video ref="video" v-if="state.photo" autoplay></video>
        <img :src="state.photoUrl" v-else>
      </div>
    </div>
    <div class="maT10">
      <el-button @click="takePhoto">
        拍照
      </el-button>
      <el-button @click="retake">
        重拍
      </el-button>
    </div>
  </div>
</template>

<script setup lang="ts" name="photo">
import axios from 'axios'
const state = reactive({
  photo: true,
  photoUrl: '',
})
const video = ref()

const takePhoto = () => {
  const canvas = document.createElement('canvas')
  canvas.width = video.value.videoWidth
  canvas.height = video.value.videoHeight
  canvas.getContext('2d').drawImage(video.value, 0, 0, canvas.width, canvas.height)
  state.photoUrl = canvas.toDataURL('image/png')

  clearVideo()
  state.photo = false
  let file = base64ImgtoFile(state.photoUrl)
  let param = new FormData()
  param.append('file', file, file.name)
  param.append('fileReName', 'true')
  let config = {
    headers: {
      'Content-Type': 'multipart/form-data',
      Authorization: 'token',  //此处是token
    },
  }

  let url = import.meta.env.VITE_API_URL + '/api/admin/file/upload-file'
  axios.post(url, param, config).then((response) => {})
}
const base64ImgtoFile = (dataurl, filename = 'file') => {
  let arr = dataurl.split(',')
  let mime = arr[0].match(/:(.*?);/)[1]
  let suffix = mime.split('/')[1]
  let bstr = atob(arr[1])
  let n = bstr.length
  let u8arr = new Uint8Array(n)
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
  }
  return new File([u8arr], `${filename}.${suffix}`, {
    type: mime,
  })
}
const clearVideo = () => {
  const stream = video.value.srcObject
  const tracks = stream.getTracks()
  tracks.forEach((track) => {
    track.stop()
  })
  video.value.srcObject = null
}

const retake = () => {
  navigator.mediaDevices
    .getUserMedia({ video: true })
    .then((stream) => {
      video.value.srcObject = stream
    })
    .catch((error) => {
      console.error(error)
    })
  state.photoUrl = ''
  state.photo = true
}

onMounted(() => {
  retake()
})
//在离开当前页面的时候把摄像头关了,不然页面一直会显示摄像头的图标
onBeforeUnmount(() => {
  video.value.srcObject = null
})
</script>

<style scoped lang="scss">
.hm {
  width: 400px;
  height: 300px;
  video,
  img {
    width: 100%;
  }
}
</style>
相关推荐
云小遥2 分钟前
Cornerstone3D 2.x升级调研
前端·数据可视化
李明卫杭州8 分钟前
浅谈JavaScript中Blob对象
前端·javascript
springfe01018 分钟前
Cesium 3D地图 图元 圆柱 图片实现
前端·cesium
meng半颗糖11 分钟前
vue3 双容器自动扩展布局 根据 内容的多少 动态定义宽度
前端·javascript·css·vue.js·elementui·vue3
yt9483212 分钟前
jquery和CSS3圆形倒计时特效
前端·css3·jquery
teeeeeeemo14 分钟前
CSS3 动画基础与技巧
前端·css·笔记·css3
年纪轻轻就扛不住16 分钟前
CSS3 渐变效果
前端·css·css3
Aisanyi20 分钟前
【鸿蒙开发】使用HMRouter路由的使用
前端·harmonyos
杉木笙25 分钟前
Flutter 代码雨实现(矩阵雨)DLC 多图层
前端·flutter
SouthernWind27 分钟前
Vista AI 演示—— 提示词优化功能
前端·vue.js