Vue calls PC camera to realize photo taking function

  • 2021-11-23 22:08:31
  • OfStack

In this paper, we share the specific code of Vue calling PC camera to realize the photo function for your reference. The specific contents are as follows

Project requirements: You can upload your avatar locally, or you can choose to shoot your avatar and upload it.

Components:

1. Camera component: Open and close the camera, draw and display pictures for uploading
2. CameraDialog component: Use ElementUI dialog component to show the UI effect of camera
3. Call CameraDialog component externally to realize the uploading function of shooting avatar
4. Native input or ElementUI upload components can be used for local uploading

Operational logic:

1. When adding, convert the avatar picture to base64 calling interface for submission, and return url address for front-end display
2. When replacing, the deletion operation is performed first, and then the new operation is performed.
3. Local upload principle and shooting upload 1

Specific implementation method:

Camera component


<template>
  <div class="camera-box">
    <video id="video" :width="videoWidth" :height="videoHeight" v-show="!imgSrc"></video>
    <canvas id="canvas" :width="videoWidth" :height="videoHeight" v-show="imgSrc"></canvas>
    <p class="camera-p">{{!imgSrc?' Tip: Please center the avatar " Photographing " Key confirmation ':''}}</p>
    <el-button type="primary" @click="setImage" v-if="!imgSrc" class="camera-btn"> Photographing </el-button>
    <el-button type="primary" v-if="imgSrc" @click="setFileUpload" class="camera-btn"> Upload </el-button>
  </div>
</template>

<script>
  import {setFileUpload, deleteFileUpload, addUserCard } from "@/api/houseApi";

  export default {
    name: 'Camera',
    props: {
      // "Must choose" CameraDialog Pop-up display status 
      show: {type: Boolean},
      // "Optional" with native input Upload locally to perform deletion when replacing 
      deleteData: {type: Object}
    },
    data() {
      return {
        videoWidth: '401',
        videoHeight: '340',
        thisCancas: null,
        thisContext: null,
        thisVideo: null,
        imgSrc: ``,
      }
    },
    mounted() {
      if (this.show) this.getCompetence()
    },
    methods: {
      /*
       *@author Brady
       *@Time 2019/9/5
       *@function   Invoke permission 
       *****************************************/
      getCompetence() {
        var _this = this
        this.thisCancas = document.getElementById('canvas')
        this.thisContext = this.thisCancas.getContext('2d')
        this.thisVideo = document.getElementById('video')
        //  Older browsers may not support it at all mediaDevices We first set the 1 Empty object 
        if (navigator.mediaDevices === undefined) {
          navigator.mediaDevices = {}
        }
        // 1 Some browsers have implemented some mediaDevices We can't just distribute 1 Objects 
        //  Use getUserMedia Because it overrides existing properties. 
        //  Here, if there is a lack of getUserMedia Property, add it. 
        if (navigator.mediaDevices.getUserMedia === undefined) {
          navigator.mediaDevices.getUserMedia = function (constraints) {
            //  First, get the existing getUserMedia( If it exists )
            var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.getUserMedia
            //  Some browsers do not support it and will return an error message 
            //  Maintain interface 1 To 
            if (!getUserMedia) {
              return Promise.reject(new Error('getUserMedia is not implemented in this browser'))
            }
            //  Otherwise, use the Promise Wrap the call to the old navigator.getUserMedia
            return new Promise(function (resolve, reject) {
              getUserMedia.call(navigator, constraints, resolve, reject)
            })
          }
        }
        var constraints = {
          audio: false,
          video: {width: this.videoWidth, height: this.videoHeight, transform: 'scaleX(-1)'}
        }
        navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
          //  Old browsers may not have srcObject
          if ('srcObject' in _this.thisVideo) {
            _this.thisVideo.srcObject = stream
          } else {
            //  Avoid using it in new browsers because it is being deprecated. 
            _this.thisVideo.src = window.URL.createObjectURL(stream)
          }
          _this.thisVideo.onloadedmetadata = function (e) {
            _this.thisVideo.play()
          }
        }).catch(err => {
          console.log(err)
        })
      },
      /*
       *@author Brady
       *@Time 2019/9/5
       *@function   Draw a picture 
       *****************************************/
      setImage() {
        var _this = this
        //  Click, canvas Draw a picture 
        _this.thisContext.drawImage(_this.thisVideo, 0, 0, _this.videoWidth, _this.videoHeight)
        //  Get a picture base64 Link 
        var image = this.thisCancas.toDataURL('image/png')
        _this.imgSrc = image
        // console.log(_this.imgSrc)
        // this.$emit('refreshDataList', this.imgSrc)
      },
      /*
       *@author Brady
       *@Time 2019/9/5
       *@function  base64 File transfer 
       *****************************************/
      dataURLtoFile(dataurl, filename) {
        var arr = dataurl.split(',')
        var mime = arr[0].match(/:(.*?);/)[1]
        var bstr = atob(arr[1])
        var n = bstr.length
        var u8arr = new Uint8Array(n)
        while (n--) {
          u8arr[n] = bstr.charCodeAt(n)
        }
        return new File([u8arr], filename, {type: mime})
      },
      /*
       *@author Brady
       *@Time 2019/9/5
       *@function   Turn off the camera 
       *****************************************/
      stopNavigator() {
        this.thisVideo.srcObject.getTracks()[0].stop()
      },
      // Upload pictures 
      setFileUpload() {
        // Edit a file - Upload face photos 
        if(this.deleteData) {
          if (this.deleteData.imagePath) {
            deleteFileUpload({id: this.deleteData.id, filePath: this.deleteData.imagePath})
              .then(res => {
                setFileUpload({image: this.imgSrc})
                  .then(res => {
                    this.$emit('fileUpload', res.retData.filePath, res.retData.imagePath)
                    addUserCard({userId: this.deleteData.userid, cardType: this.deleteData.cardType, userAuditInfo: res.retData.imagePath})
                      .then(res => {
                        this.$message({message: " Upload succeeded ", type: "success"})
                      })
                      .catch(err => {
                        console.log(err)
                      })
                  })
                  .catch(err => {
                    console.log(err)
                  })
              })
              .catch(err => {
                console.log(err)
              })
          } else {
            setFileUpload({image: this.imgSrc})
              .then(res => {
                this.$emit('fileUpload', res.retData.filePath, res.retData.imagePath)
                addUserCard({userId: this.deleteData.userid, cardType: this.deleteData.cardType, userAuditInfo: res.retData.imagePath})
                  .then(res => {
                    this.$message({message: " Upload succeeded ", type: "success"})
                  })
                  .catch(err => {
                    console.log(err)
                  })
              })
              .catch(err => {
                console.log(err)
              })
          }
        } else {
          // Adding Household - Upload face photos 
          setFileUpload({image: this.imgSrc})
            .then(res => {
              // console.log(res)
              this.$message({message: " Upload succeeded ", type: "success"})
              this.$emit('fileUpload', res.retData.filePath, res.retData.imagePath)
            })
            .catch(err => {
              console.log(err)
            })
        }
      },
    },
    watch: {
      show(val) {
        if (val) {
          this.imgSrc = ``
          this.getCompetence()
        } else {
          this.stopNavigator()
        }
      },
    }
  }
</script>

<style lang="less">
  .camera-box {
    margin: 0 auto;
    text-align: center;

    .camera-p {
      height: 17px;
      line-height: 17px;
      font-size: 12px;
      font-family: "PingFang SC";
      font-weight: 400;
      color: rgba(154, 154, 154, 1);
      text-align: left;
    }

    .camera-btn {
      margin-top: 20px;
    }

  }
</style>

CameraDialog component


<template>
  <div id="camera-dialog">
    <el-dialog
            title=" Take a photograph "
            :visible.sync="dialogVisible"
            top="5vh"
            width="481px"
            @close="dialogCancle"
            :close-on-click-modal="false"
            :before-close="dialogCancle"
    >
      <Camera :show="dialogVisible" :deleteData="deleteData" @fileUpload="fileUpload"></Camera>
      <span slot="footer" class="dialog-footer">
          <!-- <el-button @click="dialogCancle"> Take   Elimination </el-button> -->
        <!-- <el-button type="primary"> Indeed   Fixed </el-button> -->
        </span>
    </el-dialog>
  </div>
</template>

<script>
  import Camera from "@/page/house/Camera.vue"

  export default {
    name: 'CameraDialog',
    props: {
      dialogVisible: {type: Boolean},
      deleteData: {type: Object}
    },
    components: {
      Camera
    },
    data() {
      return {
        filePath: ``,
        imagePath: ``,
      }
    },
    methods: {
      // Close the pop-up window 
      dialogCancle() {
        this.$emit('dialogCancle', false, this.filePath, this.imagePath);
      },
      // Get Face Photo Address 
      fileUpload(filePath, imagePath) {
        this.filePath = filePath
        this.imagePath = imagePath
        this.dialogCancle()
      }
    }
  }
</script>

<style scoped>
</style>

External calling component


<template>
  <div>
    <div class="form-thumb">
     <img :src="filePath" alt="">
      <i class="delete-btn" @click="deleteUploadFile" v-if="deleteData.imagePath">x</i>
    </div>
    <div class="upload-btn">
       <input type="file" name="userAuditInfo" id="userAuditInfo" @change="getUploadFile" ref="inputFile">
       <el-button type="defualt" size="small" @click="localUploadFile"> Local upload </el-button>
       <el-button type="default" size="small" @click="dialogVisible=true"> Take a photograph </el-button>
     </div>
    <!--  Pop-up window for taking photos  -->
    <CameraDialog :dialogVisible="dialogVisible" @dialogCancle="dialogCancleCamera" :deleteData="deleteData" />
  </div> 
</template>

<script>
  import CameraDialog from "./CameraDialog.vue"
  import { setFileUpload, deleteFileUpload, addUserCard } from "@/api/houseApi.js"
  export default {
    data() {
      return {
        filePath: require('@/assets/images/null.png'), // ID Avatar 
        dialogVisible: false,
        // Action to delete the related fields of face photos 
        deleteData: {
          userid: this.$route.query.userId,
          id: ``,
          cardType: 4,
          imagePath: ``,
        }
   }
 },
 methods: {
      // Simulate clicking to upload face photos locally 
      localUploadFile() {
        this.$refs.inputFile.click()
      },
      // Upload face photos locally 
      getUploadFile() {
        let input = document.getElementById('userAuditInfo')
        let file = input.files[0]
        this.getBase64(file)
          .then(res => {
            if (this.deleteData.imagePath) {
              deleteFileUpload({id: this.deleteData.id, filePath: this.deleteData.imagePath})
                .then(() => {
                  this.setFileUpload(res)
                })
            } else {
              this.setFileUpload(res)
            }
          })
          .catch(err => {
            console.log(err)
          })
      },
      // Upload face photos 
      setFileUpload(res) {
        setFileUpload({image: res})
          .then(res => {
            this.filePath = res.retData.filePath
            this.deleteData.imagePath = res.retData.imagePath
            addUserCard({userId: this.deleteData.userid, cardType: this.deleteData.cardType, userAuditInfo: res.retData.imagePath})
              .then(res => {
                this.$message({message: res.retInfo, type: "success"})
                // Used to update data, this method is not shown 
                this.getInfo()
              })
              .catch(err => {
                console.log(err)
              })
          })
          .catch(err => {
            console.log(err)
          })
      },
      // Turn base64
      getBase64(file) {
        return new Promise(function (resolve, reject) {
          let reader = new FileReader();
          let imgResult = "";
          reader.readAsDataURL(file);
          reader.onload = function () {
            imgResult = reader.result;
          };
          reader.onerror = function (error) {
            reject(error);
          };
          reader.onloadend = function () {
            resolve(imgResult);
          };
        });
      },
      // Delete face photos 
      deleteUploadFile() {
        this.$confirm(` Confirm deletion ?`, ' Prompt ', {
          confirmButtonText: ' Determine ',
          cancelButtonText: ' Cancel ',
          type: 'warning'
        }).then(() => {
          deleteFileUpload({id: this.deleteData.id, filePath: this.deleteData.imagePath})
            .then(res => {
              this.$message({message: res.retInfo, type: "success"})
              this.filePath = require('@/assets/images/null.png')
              this.deleteData.imagePath = ''
            })
            .catch(err => {
              console.log(err)
            })
        }).catch(() => {});
      },
      //Dialog Cancel the pop-up window and get the uploaded face photo 
      dialogCancleCamera(str, filePath, imagePath) {
        this.dialogVisible = str
        // this.houseInfo.filePath = filePath
        // this.houseInfo.userAuditInfo = imagePath
        this.filePath = filePath
        this.deleteData.imagePath = imagePath
        this.getInfo()
      }, 
 }
  }
</script> 

<style scoped="scoped">
  .upload-btn {
    position: relative;
    margin: 20px 12px 0 0;
    text-align: right;
  }
  input#userAuditInfo {
    position: absolute;
    display: inline-block;
    width: 80px;
    height: 32px;
    top: 0;
    cursor: pointer;
    font-size: 0;
    z-index: -1;
    /*opacity: 0;*/
  }
  .delete-btn {
    position: absolute;
    top: -6px;
    right: -6px;
    display: inline-block;
    width: 16px;
    height: 16px;
    line-height: 14px;
    background: rgba(251, 135, 66, 1);
    border-radius: 8px;
    text-align: center;
    font-size: 12px;
    color: #fff;
    cursor: pointer;
  }
</style>

The above is only for reference, and the specific operation is adjusted according to the actual needs.


Related articles: