最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue 獲取攝像頭拍照并旋轉(zhuǎn)、裁剪生成新的圖片功能實現(xiàn)

 更新時間:2024年12月09日 09:34:41   作者:葉子_o  
本文給大家介紹vue 獲取攝像頭拍照并旋轉(zhuǎn)、裁剪生成新的圖片功能實現(xiàn),主要步驟包括初始化、獲取攝像頭權(quán)限、切換攝像頭、拍照以及對圖片進行旋轉(zhuǎn)和裁剪,同時提到了使用opencv.js和cropperjs進行自動裁剪和手動裁剪的實現(xiàn),感興趣的朋友跟隨小編一起看看吧

描述:
vue項目中,獲取攝像頭進行拍照,并對拍攝的圖片進行旋轉(zhuǎn)、裁剪等處理

html部分

<!-- 攝像頭列表 -->
<el-select v-model="autoVal" size="small" @change="change('auto', true)">
  <el-option
    v-for="item in vidList"
    :key="item.deviceId"
    :value="item.deviceId"
    :label="item.label"
  />
</el-select>
<!-- 拍照按鈕 -->
<el-button size="small" type="primary" @click="getImg('auto')">拍照</el-button>
<!-- 拍照畫面顯示區(qū) -->
<div id="right-bottom" v-loading="loading" class="right-bottom">
  <video v-show="videoFalg" id="video" ref="videoElement" autoplay :srcObject="videoSource" />
  <video v-show="false" id="videoElement" ref="video" autoplay :srcObject="videoSource" />
  <img id="img" src="" alt="">
  <div v-show="!a3Ora4 && !isNewModel" id="videoboder" class="videoboder" />
  <canvas v-show="false" id="canvas" />
  <!-- <video ref="videoElement" autoplay id="video"></video> -->
</div>

第一步:初始化

data() {
	resolutionRatio: '2592x1944',
	a3Ora4: false,
    videoSource: null,
    acrossOrvertical: true, // 橫版
    autoVal: '',
    videoFalg: false,
    constraints: {},
    val: '',
    loading: false,
    imgLoading: false,
    autoSelectedIndex: '',
    vidList: [],
},
mounted() {
	this.getMediaInfo()
},
methods: {
	// 第一步
	getMediaInfo() {
		if (navigator.mediaDevices.getUserMedia || navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia) {
          this.constraints = {
            video: {
              width: { ideal: 2592 },
              height: { ideal: 1944 },
              deviceId: ''
            }
          }
          // 初始化
          this.getUserMedia(this.constraints, this.deSuccess, this.error, '0')
        } else {
          alert('不支持訪問用戶媒體')
        }
	},

第二步:getUserMedia

getUserMedia(constraints, success, error, type) {
    this.videoFalg = type !== '0'
    if (navigator.mediaDevices.getUserMedia) {
      // 最新的標(biāo)準(zhǔn)API
      navigator.mediaDevices.getUserMedia(constraints)
        .then(success)
        .catch(error)
    } else if (navigator.webkitGetUserMedia) {
      // webkit核心瀏覽器
      navigator.webkitGetUserMedia(constraints, success, error)
    } else if (navigator.mozGetUserMedia) {
      // firfox瀏覽器
      navigator.mozGetUserMedia(constraints, success, error)
    } else if (navigator.getUserMedia) {
      // 舊版API
      navigator.getUserMedia(constraints, success, error)
    }
},
success(stream) {
    const video = document.getElementById('video')
    const el = document.getElementById('videoElement')
    const videoElement = this.$refs.videoElement
    // 兼容webkit核心瀏覽器
    if (this.videoFalg) {
      this.videoSource = stream
      videoElement.srcObject = stream
      el.srcObject = stream
    }
    this.loading = false
    video.onloadedmetadata = (e) => {
      video.play()
    }
},
error(err) {
    console.log(err)
},
deSuccess(stream) {
    // 獲取拍照設(shè)備列表
    this.getDevice()
}

第三步,獲取拍照設(shè)備列表

getDevice() {
	  if (!navigator.mediaDevices?.enumerateDevices) {
	     console.log('不支持')
	   } else {
	     navigator.mediaDevices
	       .enumerateDevices()
	       .then((devices) => {
	         devices.forEach((device) => {
	           if (device.kind === 'videoinput') {
	             this.vidList.push(device)
	           }
	         })
	           if (this.vidList.length && localStorage.getItem('videoSelectId')) {
	           	 // 默認選中獲取上次選擇的設(shè)備
	             this.val = localStorage.getItem('videoSelectId')
	             this.change(this.val)
	           }
	       })
	       .catch((err) => {
	         console.error(`${err.name}: ${err.message}`)
	       })
	   }
},

切換攝像頭時執(zhí)行(一定要先釋放上一次使用的攝像頭,再切換新的)

async change() {
	 // 如果 videoSource 不為空,則先釋放攝像頭?。。。。ㄖ攸c)
     if (this.videoSource !== null) {
       this.videoSource.getTracks().forEach(function (track) {
         track.stop()
       })
       this.videoSource = null
     }
     // 這里用定時器,是為了保證上次的攝像頭已經(jīng)完全釋放,再切換到新的設(shè)備(重點)
     setTimeout(() => {
       const index = this.resolutionRatio.lastIndexOf('x')
       const srtSart = this.resolutionRatio.substring(0, index)
       const srtEnd = this.resolutionRatio.substring(index + 1, val.length)
         // 存儲選中的設(shè)備id 
         localStorage.setItem('videoSelectId', this.autoVal)
         this.constraints = {
           video: {
             width: { ideal: srtSart * 1 },
             height: { ideal: srtEnd * 1 },
             deviceId: { exact: this.autoVal }
           }
         }
       }
       this.loading = true
       this.getUserMedia(this.constraints, this.success, this.error, '1')
     }, 1000)
 },

拍照,并將拍照的圖片根據(jù)需要進行旋轉(zhuǎn),獲得新的圖片

注意:以下代碼中包含多個業(yè)務(wù)邏輯,A3/A4、橫版/豎版、旋轉(zhuǎn)指定角度、自動裁剪(opencv.js)、自動裁剪識別失敗后自動彈出手動裁剪彈窗(cropperjs)等,可按需獲取, 此處只做簡單記錄

getImg(type) {
      if (!this.val && !this.autoVal) {
        this.$message.warning('請先選擇設(shè)備')
        return
      }
      this.imgLoading = true
      const el = document.getElementById('videoElement')
      const canvas = document.getElementById('canvas')
      var dpr = window.devicePixelRatio || window.webkitDevicePixelRatio || window.mozDevicePixelRatio || 1
      let base64Url = ''
      const context = canvas.getContext('2d')
      // 清空畫布
      context.clearRect(0, 0, canvas.width, canvas.height)
      context.scale(dpr, dpr)
      if (this.isNewModel || !this.isNewModel && this.a3Ora4) {
        console.log('進入a3')
        console.log('容器寬高')
        console.log('el.videoWidth', el.videoWidth)
        console.log('el.videoHeight', el.videoHeight)
        canvas.width = el.videoWidth * dpr
        canvas.height = el.videoHeight * dpr
        console.log('容器寬高*dpr')
        console.log('canvas.width', canvas.width)
        console.log('canvas.height', canvas.height)
        console.log('el.videoWidth * dpr', el.videoWidth * dpr)
        console.log('el.videoHeight * dpr', el.videoHeight * dpr)
        context.drawImage(el, 0, 0, el.videoWidth, el.videoHeight, 0, 0, canvas.width, canvas.height)
        const imgdata = context.getImageData(0, 0, canvas.width, canvas.height)
        console.log('imgdata', imgdata)
        if (this.isNewModel) {
          // 新模式拍照  ---  為識別圖片后自動裁剪邏輯,此處用到了opencv.js, 可根據(jù)需要忽略
          // eslint-disable-next-line no-undef
          const sourceMat = cv.imread('canvas')
          try {
            // eslint-disable-next-line no-undef
            const convertScaleAbsMat = getRect(sourceMat, 'canvas', this.currentScheme)
            // 有數(shù)據(jù),表示識別成功
            if (convertScaleAbsMat) {
              // eslint-disable-next-line no-undef
              showImage('canvas', convertScaleAbsMat)
            } else {
              // 識別失敗,彈出圖片裁剪彈窗手動裁剪,詳見上一篇
              base64Url = canvas.toDataURL('image/jpeg')
              this.currentType = type
              this.originBase64 = base64Url
              this.cropperVisible = true
              setTimeout(() => {
                this.imgLoading = false
              }, 1000)
              return
            }
            // 防止內(nèi)存泄漏
            if (!sourceMat.isDeleted()) {
              sourceMat.delete()
            }
          } catch (error) {
            console.error('error', error, sourceMat.isDeleted())
            setTimeout(() => {
              this.imgLoading = false
            }, 1000)
            if (!sourceMat.isDeleted()) {
              sourceMat.delete()
            }
          }
        } else {
          // 原模式a3拍照
          const d /* 圖像的總通道*/ = imgdata.data
          for (var ii = 0; ii < d.length; ii += 4) {
            const average = d[ii] * 0.1 + d[ii + 1] * 0.5 + d[ii + 2] * 0.9
            d[ii + 0] = average // 紅
            d[ii + 1] = average // 綠
            d[ii + 2] = average // 藍
          }
          // 4.把處理后的像素信息放回畫布
          context.clearRect(0, 0, canvas.width, canvas.height)
          context.putImageData(imgdata, 0, 0)
        }
        base64Url = canvas.toDataURL('image/jpeg')
        if (!this.acrossOrvertical && this.isNewModel) {
          // 新模式且是豎版
          const image = new Image()
          image.src = base64Url
          const that = this
          // 以下為旋轉(zhuǎn)圖片邏輯
          image.onload = function() {
            const newCanvas = document.createElement('canvas')
            const newContext = newCanvas.getContext('2d')
            newCanvas.width = image.height
            newCanvas.height = image.width
            newContext.clearRect(0, 0, newCanvas.width, newCanvas.height)
            newContext.translate(newCanvas.width / 2, newCanvas.height / 2)
			// rotateVal 為旋轉(zhuǎn)的角度
            newContext.rotate(that.rotateVal * Math.PI / 180)
            newContext.translate(-newCanvas.width / 2, -newCanvas.height / 2)
            newContext.drawImage(image, newCanvas.width / 2 - image.width / 2, newCanvas.height / 2 - image.height / 2, image.width, image.height)
            newContext.translate(newCanvas.width / 2, newCanvas.height / 2)
            // rotateVal 為旋轉(zhuǎn)的角度
            newContext.rotate(-that.rotateVal * Math.PI / 180)
            newContext.translate(-newCanvas.width / 2, -newCanvas.height / 2)
            newContext.restore()
            base64Url = newCanvas.toDataURL('image/jpeg')
            const blob = that.convertBase64UrlToBlob(base64Url)
            const url = window.URL.createObjectURL(that.convertBase64UrlToBlob(base64Url))
            setTimeout(() => {
              that.imgLoading = false
            }, 1000)
            that.$emit('photograph', url, blob, type)
            return
          }
        } else {
          if (this.rotateVal === 180) {
            console.log('是A4/180')
            const image = new Image()
            image.src = base64Url
            const that = this
            image.onload = function() {
            // 旋轉(zhuǎn)180度
              const newCanvas = document.createElement('canvas')
              const newContext = newCanvas.getContext('2d')
              newCanvas.width = image.width
              newCanvas.height = image.height
              newContext.clearRect(0, 0, newCanvas.width, newCanvas.height)
              newContext.translate(newCanvas.width / 2, newCanvas.height / 2)
              newContext.rotate(Math.PI)
              newContext.translate(-newCanvas.width / 2, -newCanvas.height / 2)
              newContext.drawImage(image, 0, 0, image.width, image.height)
              newContext.translate(newCanvas.width / 2, newCanvas.height / 2)
              console.log('旋轉(zhuǎn)180:', that.rotateVal, -that.rotateVal * Math.PI / 180)
              newContext.rotate(-Math.PI)
              newContext.translate(-newCanvas.width / 2, -newCanvas.height / 2)
              newContext.restore()
              base64Url = newCanvas.toDataURL('image/jpeg')
              const blob = that.convertBase64UrlToBlob(base64Url)
              const url = window.URL.createObjectURL(that.convertBase64UrlToBlob(base64Url))
              setTimeout(() => {
                that.imgLoading = false
              }, 1000)
              that.$emit('photograph', url, blob, type)
            }
          } else {
            const blob = this.convertBase64UrlToBlob(base64Url)
            const url = window.URL.createObjectURL(this.convertBase64UrlToBlob(base64Url))
            setTimeout(() => {
              this.imgLoading = false
            }, 1000)
            this.$emit('photograph', url, blob, type)
          }
        }
      } else if (!this.isNewModel && !this.a3Ora4) {
        console.log('進入a4')
        // 橫版
        if (this.acrossOrvertical) {
          canvas.width = el.videoWidth * dpr
          canvas.height = el.videoHeight * dpr
          context.drawImage(el, 200, 200, el.videoWidth - 200, el.videoHeight - 200, 0, 0, (el.videoWidth + 170) * dpr, (el.videoHeight + 230) * dpr)
          const imgdata = context.getImageData(0, 0, canvas.width, canvas.height)
          const d /* 圖像的總通道*/ = imgdata.data
          // 2.遍歷每一個像素
          for (let i = 0; i < d.length; i += 4) {
            const average = d[i] * 0.1 + d[i + 1] * 0.5 + d[i + 2] * 0.9
            d[i + 0] = average // 紅
            d[i + 1] = average // 綠
            d[i + 2] = average // 藍
          }
          // 4.把處理后的像素信息放回畫布
          context.clearRect(0, 0, canvas.width, canvas.height)
          context.putImageData(imgdata, 0, 0)
          base64Url = canvas.toDataURL('image/jpeg')
          if (this.rotateVal === 180) {
            console.log('是A4/180')
            const image = new Image()
            image.src = base64Url
            const that = this
            image.onload = function() {
            // 旋轉(zhuǎn)180度
              const newCanvas = document.createElement('canvas')
              const newContext = newCanvas.getContext('2d')
              newCanvas.width = image.width
              newCanvas.height = image.height
              newContext.clearRect(0, 0, newCanvas.width, newCanvas.height)
              newContext.translate(newCanvas.width / 2, newCanvas.height / 2)
              newContext.rotate(Math.PI)
              newContext.translate(-newCanvas.width / 2, -newCanvas.height / 2)
              newContext.drawImage(image, 0, 0, image.width, image.height)
              newContext.translate(newCanvas.width / 2, newCanvas.height / 2)
              console.log('旋轉(zhuǎn)180:', that.rotateVal, -that.rotateVal * Math.PI / 180)
              newContext.rotate(-Math.PI)
              newContext.translate(-newCanvas.width / 2, -newCanvas.height / 2)
              newContext.restore()
              base64Url = newCanvas.toDataURL('image/jpeg')
              const blob = that.convertBase64UrlToBlob(base64Url)
              const url = window.URL.createObjectURL(that.convertBase64UrlToBlob(base64Url))
              setTimeout(() => {
                that.imgLoading = false
              }, 1000)
              that.$emit('photograph', url, blob, type)
            }
          } else {
            const blob = this.convertBase64UrlToBlob(base64Url)
            const url = window.URL.createObjectURL(this.convertBase64UrlToBlob(base64Url))
            setTimeout(() => {
              this.imgLoading = false
            }, 1000)
            this.$emit('photograph', url, blob, type)
          }
        } else {
          // 豎版
          canvas.width = el.videoWidth * dpr
          canvas.height = el.videoHeight * dpr
          context.drawImage(el, 200, 200, el.videoWidth - 200, el.videoHeight - 200, 0, 0, (el.videoWidth + 170) * dpr, (el.videoHeight + 230) * dpr)
          const imgdata = context.getImageData(0, 0, canvas.width, canvas.height)
          const d /* 圖像的總通道*/ = imgdata.data
          // 2.遍歷每一個像素
          for (let i = 0; i < d.length; i += 4) {
            const average = d[i] * 0.1 + d[i + 1] * 0.5 + d[i + 2] * 0.9
            d[i + 0] = average // 紅
            d[i + 1] = average // 綠
            d[i + 2] = average // 藍
          }
          // 4.把處理后的像素信息放回畫布
          context.clearRect(0, 0, canvas.width, canvas.height)
          context.putImageData(imgdata, 0, 0)
          base64Url = canvas.toDataURL('image/jpeg')
          const image = new Image()
          image.src = base64Url
          const that = this
          image.onload = function() {
            // 旋轉(zhuǎn)90度
            const newCanvas = document.createElement('canvas')
            const newContext = newCanvas.getContext('2d')
            newCanvas.width = image.height
            newCanvas.height = image.width
            newContext.clearRect(0, 0, newCanvas.width, newCanvas.height)
            newContext.translate(newCanvas.width / 2, newCanvas.height / 2)
            newContext.rotate(that.rotateVal * Math.PI / 180)
            newContext.translate(-newCanvas.width / 2, -newCanvas.height / 2)
            newContext.drawImage(image, newCanvas.width / 2 - image.width / 2, newCanvas.height / 2 - image.height / 2, image.width, image.height)
            newContext.translate(newCanvas.width / 2, newCanvas.height / 2)
            newContext.rotate(-that.rotateVal * Math.PI / 180)
            newContext.translate(-newCanvas.width / 2, -newCanvas.height / 2)
            newContext.restore()
            base64Url = newCanvas.toDataURL('image/jpeg')
            const blob = that.convertBase64UrlToBlob(base64Url)
            const url = window.URL.createObjectURL(that.convertBase64UrlToBlob(base64Url))
            setTimeout(() => {
              that.imgLoading = false
            }, 1000)
            that.$emit('photograph', url, blob, type)
          }
        }
      }
    },

到此這篇關(guān)于vue 獲取攝像頭拍照,并旋轉(zhuǎn)、裁剪生成新的圖片的文章就介紹到這了,更多相關(guān)vue 獲取攝像頭拍照內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue3+vite項目配置ESlint、pritter插件過程

    vue3+vite項目配置ESlint、pritter插件過程

    這篇文章主要介紹了vue3+vite項目配置ESlint、pritter插件過程,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Antd中單個DatePicker限定時間輸入范圍操作

    Antd中單個DatePicker限定時間輸入范圍操作

    這篇文章主要介紹了Antd中單個DatePicker限定時間輸入范圍操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • vue非父子組件通信問題及解決方法

    vue非父子組件通信問題及解決方法

    這篇文章主要介紹了vue非父子組件通信問題及解決方法,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-06-06
  • Vue3使用pdfjs-dist實現(xiàn)PDF文件瀏覽器預(yù)覽功能

    Vue3使用pdfjs-dist實現(xiàn)PDF文件瀏覽器預(yù)覽功能

    本文介紹在Vue3項目中集成pdfjs-dist以實現(xiàn)PDF預(yù)覽功能的過程,包括安裝步驟、創(chuàng)建Vue組件、使用方法及注意事項,涉及PDF文件來源、性能優(yōu)化、錯誤處理、樣式定制、兼容性等問題,并提供了解決方案,需要的朋友可以參考下
    2026-03-03
  • vue中利用mqtt服務(wù)端實現(xiàn)即時通訊的步驟記錄

    vue中利用mqtt服務(wù)端實現(xiàn)即時通訊的步驟記錄

    前些日子了解到mqtt這樣一個協(xié)議,可以在web上達到即時通訊的效果,所以下面這篇文章主要給大家介紹了關(guān)于vue中如何利用mqtt服務(wù)端實現(xiàn)即時通訊的相關(guān)資料,需要的朋友可以參考下
    2021-07-07
  • Vue 遞歸多級菜單的實例代碼

    Vue 遞歸多級菜單的實例代碼

    這篇文章主要介紹了Vue 遞歸多級菜單的實例代碼,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-05-05
  • Vue包大小優(yōu)化的實現(xiàn)(從1.72M到94K)

    Vue包大小優(yōu)化的實現(xiàn)(從1.72M到94K)

    這篇文章主要介紹了Vue包大小優(yōu)化的實現(xiàn)(從1.72M到94K),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • Ant?Design-vue?解決input前后空格問題(推薦)

    Ant?Design-vue?解決input前后空格問題(推薦)

    最近做項目遇到這樣一個問題輸入框不允許有前后空格但字符中間可以有空格,怎么解決這個問題呢,接下來小編把ant?Design-vue?解決input前后空格問題的實現(xiàn)代碼分享給大家,感興趣的朋友一起看看吧
    2022-10-10
  • vue3中watch和watchEffect實戰(zhàn)梳理

    vue3中watch和watchEffect實戰(zhàn)梳理

    這篇文章主要介紹了vue3中watch和watchEffect實戰(zhàn)梳理,watch和watchEffect都是vue3中的監(jiān)聽器,但是在寫法和使用上是有區(qū)別的。下文介紹他們之間的方法及區(qū)別,需要的朋友可以參考一下
    2022-07-07
  • vue項目出現(xiàn)ERESOLVE could not resolve問題及解決

    vue項目出現(xiàn)ERESOLVE could not resolve問題及解決

    這篇文章主要介紹了vue項目出現(xiàn)ERESOLVE could not resolve問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10

最新評論

驻马店市| 盘锦市| 时尚| 古浪县| 连平县| 红安县| 五华县| 会东县| 施甸县| 夏河县| 武威市| 台北县| 漾濞| 富蕴县| 宁晋县| 灵石县| 临江市| 湘西| 九龙城区| 扎鲁特旗| 温州市| 颍上县| 黄大仙区| 全州县| 榆社县| 怀化市| 南宫市| 柘城县| 徐州市| 仁怀市| 大同市| 临沂市| 剑川县| 仙居县| 育儿| 津市市| 清水县| 二连浩特市| 虹口区| 恩施市| 玉林市|