前端调用电脑摄像头

项目中需要前端调用,所以做了如下操作
先看一下效果吧
主要是基于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>
相关推荐
方安乐1 分钟前
vite+vue+js项目使用ts报错
前端·javascript·vue.js
韩立23334 分钟前
Vue 3.5 升级指南
前端·vue.js
子兮曰11 分钟前
🚀别再乱写package.json了!这些隐藏技巧让项目管理效率提升300%
前端·javascript·npm
我叫汪枫16 分钟前
Spring Boot图片验证码功能实现详解 - 从零开始到完美运行
java·前端·javascript·css·算法·html
小桥风满袖20 分钟前
极简三分钟ES6 - ES8中async,await
前端·javascript
William_cl1 小时前
MVC 中 AJAX 与前后端交互深度实战(含独家避坑与场景化方案)
ajax·mvc·交互
一直在学习的小白~1 小时前
node_modules 明明写进 .gitignore,却还是被 push/commit 的情况
前端·javascript·vue.js
前端小超超1 小时前
如何配置capacitor 打包的ios app固定竖屏展示?
前端·ios·web app
nightunderblackcat1 小时前
新手向:从零理解LTP中文文本处理
前端·javascript·easyui
kyle~1 小时前
python---PyInstaller(将Python脚本打包为可执行文件)
开发语言·前端·python·qt