基本上同时兼容安卓和苹果的插件都需要付费,这里我找了2个好用的免费插件
1.仅支持安卓:自定义身份证相机(支持蒙版自定义),内置蒙版,照片预览,身份证裁剪 - DCloud 插件市场、
2.支持iOS(已测),支持Android(未测,应该也可以用):
自定义相机 - DCloud 插件市场
第一个插件使用方法(仅支持安卓):
创建一个realName.vue文件
<view class="personalInfo" style="margin-top: 20rpx;"><view class="label" style="margin-bottom: 8rpx;"><view class="blue"></view><view class="title">证件图片</view></view><view class="tips">请拍摄或上传身份证原件照片,确保照片完整清晰</view><view class="imgBox"><view class="front"><image :src="frontImg" :class="platform == 'ios' ? 'transformImg' : ''" @click="uploadImgNew('front')"/><view class="frontBtn" @click="uploadImgNew('front')" v-if="frontImg == ''">上传人像面</view></view><view class="back"><image :src="backImg" :class="platform == 'ios' ? 'transformImg' : ''" @click="uploadImgNew('back')"/><view class="backBtn" @click="uploadImgNew('back')" v-if="backImg == ''">上传国徽面</view></view></view></view>
export default {data () {return {frontImg: '',backImg: '',canvasSiz:{width:188,height:273},flag: true}},
methods:{uploadImgNew(types){console.log('打开相机');let platform = uni.getSystemInfoSync().platformif(!this.flag){uni.showToast({title: '图片正在上传中,请误做其他操作', icon: 'none'})return}if(platform == 'ios'){// ios的另外用了别的插件,下面会讲到uni.navigateTo({url: `./idcard?dotype=${types == 'front' ? 'face' : 'badge'}`})}else{var cameraModule = uni.requireNativePlugin('yun-camerax-module');//无需蒙版可将type设置为非参数值,例如 type:99cameraModule.takePhoto({ type: types == 'front' ? 0 : 1, imageIndex: 2, fullSrc: true,text: types == 'front' ? '将身份证正面置于此区域内并对齐边缘' : '将身份证背面置于此区域内并对齐边缘'}, res => {console.log(res);uni.showModal({title: '提示',// content: JSON.stringify(res),content: '请再次确认使用该图',success: (res1) => {if (res1.confirm) {console.log('用户点击确定',res);this.upLoadImg(res.file,types)} else if (res1.cancel) {console.log('用户点击取消');}}});});}},async upLoadImg(path,type) {setTimeout(()=>{uni.showToast({title: '上传中',icon: 'none'})this.flag = falseuni.uploadFile({url: 'xxxxxx/upload', //后端上传接口filePath: path,name: "file",success: (res) => {console.log('res222',res);if(JSON.parse(res.data).code == 0){console.log('JSON.parse(res.data)',JSON.parse(res.data));if(type == 'front'){this.frontImg = JSON.parse(res.data).data.rel_paththis.$forceUpdate()}else{this.backImg = JSON.parse(res.data).data.rel_paththis.$forceUpdate()}this.flag = true }else{uni.showToast({title: JSON.parse(res.data).msg,icon: 'none'})}},fail(e) {this.showTip("上传图片失败");},});},300)},
第二个插件使用方法:
需要用到live-pusher直播推流,在manifest.json中勾选,真机调试需要重新打自定义基座再重新运行
为了防止样式兼容问题,另外需配置如下:
在同级目录下创建idcard.nvue文件
然后把下面代码整个copy进去
<template><view class="live-camera" :style="{ width: windowWidth, height: windowHeight }"><view class="preview" :style="{ width: windowWidth, height: windowHeight - 65 }"><live-pusherid="livePusher"ref="livePusher"class="livePusher"mode="FHD"beauty="0"whiteness="0":aspect="aspect"min-bitrate="1000"audio-quality="16KHz":device-position="back":auto-focus="true":muted="true":enable-camera="true":enable-mic="false":zoom="false"@statechange="statechange":style="{ width: cameraWidth, height: cameraHeight }"></live-pusher><!--提示语--><cover-view class="remind"><text class="remind-text" style="">{{ message }}</text></cover-view><!--辅助线--><cover-view class="outline-box" :style="{ width: windowWidth, height: windowHeight - 80}"><cover-imageclass="outline-img":src="dotype == 'face' ? '/static/live-camera/outline/idcardface.png' : '/static/live-camera/outline/idcardbadge.png'"style=""></cover-image></cover-view></view><view class="menu"><!--底部菜单区域背景--><cover-image class="menu-mask" src="/static/live-camera/bar.png"></cover-image><!--返回键--><cover-image class="menu-back" @tap="back" src="/static/live-camera/back.png"></cover-image><!--快门键--><cover-image class="menu-snapshot" @tap="snapshot" src="/static/live-camera/shutter.png"></cover-image><!--反转键--><cover-image class="menu-flip" @tap="flip" src="/static/live-camera/flip.png"></cover-image></view></view>
</template><script>
let _this = null;
export default {data() {return {poenCarmeInterval: null, //打开相机的轮询dotype: 'face', //操作类型message: '', //提示aspect: '2:3', //比例cameraWidth: '', //相机画面宽度cameraHeight: '', //相机画面宽度windowWidth: '', //屏幕可用宽度windowHeight: '', //屏幕可用高度camerastate: false, //相机准备好了livePusher: null, //流视频对象snapshotsrc: null //快照};},onLoad(e) {console.log('e',e);_this = this;this.dotype = e.dotype;this.initCamera();},onReady() {uni.showToast({title: '相机加载中...',icon: 'none',duration: 800})this.livePusher = uni.createLivePusherContext('livePusher', this);console.log('this.livePusher',this.livePusher);this.startPreview(); //开启预览并设置摄像头this.poenCarme();},methods: {//轮询打开poenCarme() {//#ifdef APP-PLUSif (plus.os.name == 'Android') {console.log('111');this.poenCarmeInterval = setInterval(function() {console.log(_this.camerastate);if (!_this.camerastate) _this.startPreview();}, 2500);}else{console.log('2222');}//#endif},//初始化相机initCamera() {//处理安卓手机异步授权问题uni.getSystemInfo({success: (res) => {console.log('resxxxx',res);this.windowWidth = res.windowWidth;this.windowHeight = res.windowHeight;this.cameraWidth = res.windowWidth;this.cameraHeight = res.windowWidth * 1.5;}});},//开始预览startPreview() {console.log('执行开始预览');this.livePusher.startPreview({success: (a) => {console.log('aaa',a);}});},//停止预览stopPreview() {this.livePusher.stopPreview({success: a => {console.log('停止预览',a);this.camerastate = false; //标记相机未启动}});},//状态statechange(e) {//状态改变console.log(e);if (e.detail.code == 1007) {_this.camerastate = true;} else if (e.detail.code == -1301) {_this.camerastate = false;}},//返回back() {uni.navigateBack();},//抓拍snapshot() {this.livePusher.snapshot({success: e => {console.log('快门',e);this.snapshotsrc = e.message.tempImagePath;this.stopPreview();this.setImage();uni.navigateBack();}});},//反转flip() {this.livePusher.switchCamera();},//设置setImage() {let pages = getCurrentPages();let prevPage = pages[pages.length - 2]; //上一个页面//直接调用上一个页面的setImage()方法,把数据存到上一个页面中去prevPage.$vm.setImage({ path: this.snapshotsrc, dotype: this.dotype });}}
};
</script><style lang="scss">.live-camera {.preview {justify-content: center;align-items: center;.outline-box {position: absolute;top: 0;left: 0;bottom: 0;z-index: 99;align-items: center;justify-content: center;.outline-img {width: 750rpx;height: 1125rpx;}}.remind {position: absolute;top: 880rpx;width: 750rpx;z-index: 100;align-items: center;justify-content: center;.remind-text {color: #dddddd;font-weight: bold;}}}.menu {position: absolute;left: 0;bottom: 0;width: 750rpx;height: 180rpx;z-index: 98;align-items: center;justify-content: center;.menu-mask {position: absolute;left: 0;bottom: 0;width: 750rpx;height: 180rpx;z-index: 98;}.menu-back {position: absolute;left: 30rpx;bottom: 50rpx;width: 80rpx;height: 80rpx;z-index: 99;align-items: center;justify-content: center;}.menu-snapshot {width: 130rpx;height: 130rpx;z-index: 99;}.menu-flip {position: absolute;right: 30rpx;bottom: 50rpx;width: 80rpx;height: 80rpx;z-index: 99;align-items: center;justify-content: center;}}
}</style>
因为第一次使用nvue,代码整个都成灰色,需要在vscode设置中按下图配置,代码就会和.vue文件一样变彩色,方便阅读
在realName.vue文件中加入:
<canvas id="canvas-clipper" canvas-id="canvas-clipper" type="2d" :style="{width: canvasSiz.width+'px',height: canvasSiz.height+'px',position: 'absolute',left:'-500000px',top: '-500000px'}" />
这里用到canvas是为了把live-pusher横屏拍摄的身份证裁剪
methods:{//设置图片setImage(e) {console.log('跳回这个页面',e);let type = e.dotype == 'face' ? 'front' : 'back'//显示在页面console.log('type',type);// this.upLoadImg(e.path,type)this.zjzClipper(e.path,type)},//证件照裁切zjzClipper(path,type) {uni.getImageInfo({src: path,success: (image) => {console.log('image',image);this.canvasSiz.width =188;this.canvasSiz.height =273;//因为nvue页面使用canvas比较麻烦,所以在此页面上处理图片let ctx = uni.createCanvasContext('canvas-clipper', this);ctx.drawImage(path,parseInt(0.15 * image.width),parseInt(0.17 * image.height),parseInt(0.69 * image.width),parseInt(0.65 * image.height),0,0,188,273);ctx.draw(false, () => {uni.canvasToTempFilePath({destWidth: 188,destHeight: 273,canvasId: 'canvas-clipper',fileType: 'jpg',success: (res) => {// this.savePhoto(res.tempFilePath);// this.frontImg = res.tempFilePaththis.upLoadImg(res.tempFilePath,type)}},this);});}});},
如果想保存拍摄的照片还可以使用下面方法
savePhoto(path){this.imagesrc = path;//保存到相册uni.saveImageToPhotosAlbum({filePath: path,success: () => {uni.showToast({title: '已保存至相册',duration: 2000});}});},
realName.vue的css样式部分
.personalInfo{padding: 27rpx 30rpx;box-sizing: border-box;background-color: #fff;.label{display: flex;align-items: center;margin-bottom: 50rpx;.blue{width: 8rpx;height: 30rpx;background-color: #3E71FE;margin-right: 12rpx;}.title{font-weight: 500;font-size: 32rpx;color: #1D1B1A;}}.realName{display: flex;align-items: center;margin-bottom: 30rpx;padding-left: 20rpx;box-sizing: border-box;.name{font-weight: 500;font-size: 28rpx;color: #1D1B1A;}}.tips{font-weight: normal;font-size: 24rpx;color: #929292;margin-bottom: 30rpx;}.lineBottom{width: 650rpx;height: 2rpx;background: #F5F5F5;margin: auto;margin-bottom: 30rpx;}.imgBox{display: flex;flex-direction: column;justify-content: space-between;padding: 0 82rpx;box-sizing: border-box;.front{position: relative;width: 526rpx;height: 288rpx;border-radius: 20rpx 20rpx 20rpx 20rpx;margin-bottom: 28rpx;background: url('https://res.qyjpay.cn/static/res/yewuban-smrz-zhengmian.png') no-repeat center;background-size: contain;.frontBtn{position: absolute;bottom: 50rpx;left: 123rpx;width: 280rpx;height: 90rpx;line-height: 90rpx;background: #3E71FE;box-shadow: 0rpx 8rpx 12rpx 1rpx rgba(62,113,254,0.15);border-radius: 45rpx 45rpx 45rpx 45rpx;font-size: 32rpx;color: #FFFFFF;font-weight: normal;text-align: center;}image{position: absolute;left: 0;top: 0;width: 526rpx;height: 288rpx;border-radius: 20rpx 20rpx 20rpx 20rpx;}}.transformImg{position: absolute;left: 120rpx !important;top: -120rpx !important;transform: rotate(-90deg);width: 288rpx !important;height: 526rpx !important;z-index: 999;}.back{position: relative;width: 526rpx;height: 288rpx;border-radius: 20rpx 20rpx 20rpx 20rpx;background: url('https://res.qyjpay.cn/static/res/yewuban-smrz-fanmian.png') no-repeat center;background-size: contain;.backBtn{position: absolute;bottom: 50rpx;left: 123rpx;width: 280rpx;height: 90rpx;line-height: 90rpx;background: #3E71FE;box-shadow: 0rpx 8rpx 12rpx 1rpx rgba(62,113,254,0.15);border-radius: 45rpx 45rpx 45rpx 45rpx;font-size: 32rpx;color: #FFFFFF;font-weight: normal;text-align: center;}image{position: absolute;left: 0;top: 0;width: 526rpx;height: 288rpx;border-radius: 20rpx 20rpx 20rpx 20rpx;}}}}
里面的图片和结构根据项目需求自行修改