<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)
// 上傳拍照信息 調用接口上傳圖片 ......... // 保存到本地 let ADOM = document.createElement('a') ADOM.href = this.headImgSrc ADOM.download = new Date().getTime() + '.jpeg' ADOM.click() }, // 關閉攝像頭 closeCamera () { if (!this.$refs['video'].srcObject) return let stream = this.$refs['video'].srcObject let tracks = stream.getTracks() tracks.forEach(track => { track.stop() }) this.$refs['video'].srcObject = null }, } } </script>
HTML 部分:vue
<input ref="file" type="file" accept="image/*" capture="user">
JS 部分: 接口使用的Vuex調用 可忽略 ajax
// 壓縮圖片 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) },
結語; 業務代碼刪了致使有點亂了,有不懂或疑問之處歡迎留言;vuex