H5调取摄像头拍照

3,186 阅读3分钟

2021-5-11更新:

最新版本H5调取摄像头:

juejin.cn/post/696093…

2021-3-11更新:

同样还是这个h5项目,但是这次是从小程序端打开,由于之前是调取的安卓方法唤起摄像头,所以在小程序端并不适用,我又想起了使用标签来唤起摄像头

摄像头 <input type="file" accept="image/*" capture="camera">

本来是使用当前环境判断的方法,但是不知为何无法准确判断小程序环境,于是最后决定在小程序url后面加一个参数

?isWechat=1

然后进入页面时候获取这个参数做判断显示标签调取摄像头的按钮,隐藏安卓调取摄像头的按钮。

<div v-if="isWechat" class="camera-btn">  
<input ref="file" type="file" class="file" accept="image/*" @change="h5CompressImage" capture="user"> 
 <x-button style="margin-top:10px;" class="search-btn">点击拍摄</x-button>
</div>
<div v-else class="camera-btn"> 
 <x-button style="margin-top:10px;" class="search-btn" @click.native = "checkCamera">点击拍摄</x-button>
</div>

h5CompressImage方法和下面方法差不多,只是取file是直接获取不像安卓要通过base64转为file

之前的:

part1: 

       最近要做一个录入人脸自拍的功能,经过一番调查,发现了以下方法可以再看浏览器端进行摄像头调取 

摄像头 <input type="file" accept="image/*" capture="camera">

前置摄像头调用</h3> <input type="file" accept="image/*" capture="user"> (并没有前置)

开开心心本地测试完美运行,但是故事没有结束,然后打包上线后~

(ps:项目是安卓项目通过打开线h5页面调取摄像头拍照提交)

然后蒙了,打开安卓app测试后,发现只能打开文件选择,无法直接调取摄像头,之后无论怎么改都不可以

然后我尝试了下使用线上页面的链接,从浏览器而不是安卓app内打开,发现浏览器端是可以调取摄像头的,但是在安卓中使用它内置的浏览器打开却只能文件选择。

part2: 

准备通过安卓那边提供的方法,通过方法吊起摄像头

相关代码:

在main.js中全局添加(也可以在页面单独引入)

document.addEventListener('clplusready', function() { Vue.prototype.plus = clplus;});

然后通过这段代码调取摄像头

checkCamera() {  
let _this = this; //这个地方最后一步卡了我好久,一只无法获取图片,因为this指向 
//调取摄像头  
this.plus.clCamera.picture(function (result) {    
    var a = JSON.parse(result); //将拍照后返回的数组字符串转化为对象   
    var b = a[0].image;    //获取里面的base64图片
    let getData =`data:image/jpeg;base64,${b}`;//拼接成完整base64格式   
     _this.compressImage(getData);  //把得到的base64数据传入其他方法
}, function (error) {   
     alert(error) 
 }, {    
     "destinationType": "0",  //安卓回调设置0返回base64图片,1返回图片路径
     "pictureSourceType": "1" 固定传1   是打开相机   传0是打开图库
 });},



获取到base64数据后传入方法,把base64转化为文件流file格式,然后对数据进行方向和图片尺寸;大小处理

base64toFile (dataurl, filename = 'picture') { 
    let arr = dataurl.split(',') 
    let mime = arr[0].match(/:(.*?);/)[1]  
    let suffix = mime.split('/')[1]  
    let bstr = atob(arr[1])  
    let n = bstr.length  
    let u8arr = new Uint8Array(n)  
    while (n--) {    
        u8arr[n] = bstr.charCodeAt(n) 
    }  
    return new File([u8arr], `${filename}.${suffix}`, {   
        type: mime  
    })
}



然后通过方法处理图片把图片旋转正,压缩等然后传入upload把图片上传
// 压缩图片 and 旋转角度纠正
compressImage (getData) {  
let file = this.base64toFile(getData);  
let _this = this  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') 
// 图片大小  大于100KB 则压缩  
const isLt2MB = file.size < 102400  
// 通过 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 < 500 && imgHeight < 500 && !Orientation) return _this.upload(file)    
if (isLt2MB && imgWidth < 500 && imgHeight < 500 && +Orientation === 1) return _this.upload(file)    // 大于2MB 、img宽高 > 500 则进行压缩    if (!isLt2MB || imgWidth >= 500 || imgHeight >= 500) {      
// 最大尺寸      let maxWidth = 500      let maxHeight = 500      // 图片尺寸超过 500 X 500 的限制      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     
 // 图片大小超过 100k 但未旋转  则只需要进行图片压缩     
 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     
 }    
}   
 // 调用接口上传   
 // _this.upAppUserFaceByBase64()    
// 通过文件流格式上传   
 canvas.toBlob(function (blob) {  
    _this.upload(blob)    
}, 'image/jpeg', 1) 
 }
},

上传文件流处理

得到的file
var formdata = new FormData();
formdata.append("file",file,file.name)
然后上传formdata