进入正题
1. PC端调用摄像头拍照上传base64格式到后台,这个没什么花里胡哨的骚操作,直接看代码 (canvas + video)
2. 移动端调用手机前置摄像头人脸录入、及图片旋转矫正、压缩上传base64格式/文件流格式;移动端幺蛾子就多了,比如部分手机打开的不是前置摄像头,部分手机拍照图片旋转了,高清手机拍的图片非常大........
介绍: 1. 通过input 开启手机前置摄像头 accept="image/*" 为开启摄像头 capture="user" 为开启前置摄像头 (微信公众号的话可以微信jssdk,但它不支持前置摄像头,默认后置,所以没用)
2. 通过 exif.js 判断旋转了多少度在通过canvas矫正
3. 图片太大或超过规定尺寸则通过canvas压缩
HTML 部分:
JS 部分: 接口使用的Vuex调用 可忽略
// 压缩图片 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) },
结语; 业务代码删了导致有点乱了,有不懂或疑问之处欢迎留言;