vue实现PC端调用摄像头拍照、移动端调用手机前置摄像头人脸录入、及图片旋转矫正、压缩上传base64格式/文件格式

vue实现PC端调用摄像头拍照、移动端调用手机前置摄像头人脸录入、及图片旋转矫正、压缩上传base64格式/文件格式:
注: 双端人脸录入需求

1. PC端调用摄像头拍照上传base64格式到后台,这个没什么花里胡哨的骚操作,直接看代码 (canvas + video)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<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)

   # // 上传拍照信息 调用接口上传图片 .........

# // 保存到本地
this.dialogCamera = false
let ADOM = document.createElement('a')
ADOM.href = this.headImgSrc
ADOM.download = new Date().getTime() + '.jpeg'
ADOM.click()
},
# // 关闭摄像头
closeCamera () {
if (!this.$refs['video'].srcObject) {
this.dialogCamera = false
return
}
let stream = this.$refs['video'].srcObject
let tracks = stream.getTracks()
tracks.forEach(track => {
track.stop()
})
this.$refs['video'].srcObject = null
},
}
}
</script>

2. 移动端调用手机前置摄像头人脸录入、及图片旋转矫正、压缩上传base64格式/文件流格式;移动端幺蛾子就多了,比如部分手机打开的不是前置摄像头,部分手机拍照图片旋转了,高清手机拍的图片非常大……..

  1. 通过input 开启手机前置摄像头accept=”image/*”为开启摄像头capture=”user”为开启前置摄像头;微信公众号的话可以微信jssdk,但它不支持前置摄像头,默认后置)
  2. 通过 exif.js 判断旋转了多少度在通过canvas矫正
  3. 图片太大或超过规定尺寸则通过canvas压缩

    HTML 部分:

    1
    <input ref="file" type="file" accept="image/*" capture="user">

JS 部分: 接口使用的Vuex调用可忽略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
<script>
export default {
data () {
return {}
},
methods: {
# // 压缩图片 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)
}
}
}
</script>

结语; 无关紧要代码删的导致有点乱了,有不懂或疑问之处欢迎留言;

文章目录
  1. 1. 1. PC端调用摄像头拍照上传base64格式到后台,这个没什么花里胡哨的骚操作,直接看代码 (canvas + video)
  2. 2. 2. 移动端调用手机前置摄像头人脸录入、及图片旋转矫正、压缩上传base64格式/文件流格式;移动端幺蛾子就多了,比如部分手机打开的不是前置摄像头,部分手机拍照图片旋转了,高清手机拍的图片非常大……..
  • HTML 部分:
  • JS 部分: 接口使用的Vuex调用可忽略
  • ,