在小程序还发过程中,经常会遇到对证件(身份证、驾驶证、营业执照)的扫描识别认证功能;这里我根据自己的经历借鉴总结一下相关的方法;
第一步需要在微信小程序后台添加第三方插件,设置-第三方设置-插件管理,输入**ocr支持**搜索添加就可以了;
OCR支持插件添加成功之后需要到开放社区购买识别次数,可以根据自己公司的业务需求量购买;(个人觉得有点贵)
在 app.json 中声明引入插件,version 使用最新版本,provider 是OCR支持的 AppID;
"plugins": {
"ocr-plugin": {
"version": "3.1.1",
"provider": "wx4418e3e031e551be"
}
}
在使用OCR支持的页面 json 中引入组件
{
"usingComponents": {
"ocr-navigator": "plugin://ocr-plugin/ocr-navigator"
}
}
页面使用
//wxml
<ocr-navigator bind:onSuccess="success" certificateType="idCard" opposite="{{false}}">
<button type="primary">身份证正面识别</button>
</ocr-navigator>
<ocr-navigator bind:onSuccess="success" certificateType="idCard" opposite="{{true}}">
<button type="primary">身份证反面识别</button>
</ocr-navigator>
//js
Page({
data:{
name:'',
id:''
},
success(e){
console.log(e.detail)
this.setData({
name:e.detail.name.text,
id:e.detail.id.text
})
}
})
注意:certificateType 类型不同属性也不同可以参考:OCR支持开发文档
申请地址:http://ai.baidu.com/?track=cp:aipinzhuan|pf:pc|pp:AIpingtai|pu:title|ci:|kw:10005792
开放能力-文字识别 ,这里有身份证、银行卡、营业执照、护照、出生证明等识别服务;
按照个人需要填写信息,创建应用之后,在应用列表可以查看对应的 API Key 、Secret Key、AppID 等信息;
在使用之前,我们需要将百度OCR接口域名配置在微信小程序后台的合法域名中(https://aip.baidubce.com);
接口、入参参考:技术文档
获取身份证图片
// 点击扫证,可拍照、可选择本机图片
getImage(){
let that = this
wx.showActionSheet({
itemList: ['拍照','相册'],
success(res){
let index = res.tabIndex;
if(index == 0){
that.gotophoto();
}else{
that.getAlbum();
}
}
})
},
//从相册选择图片
getAlbum(){
let that = this;
wx.chooseImage({
count: 1,
sourceType: ['album'],
success:function(res){
let path = res.tempFilePaths[0];
that.getBase64Path(path).then(base64=>{
that.ocrCard(base64).then(res=>{
//这里就是扫描的结果
console.log(res);
})
});
}
})
},
//本地转化为base64编码
getBase64Path(path){
return new Prmise((resolve,reject)=>{
wx.getFileSystemManager().readFile({
filePath: path,
encoding: 'base64',
success: function (res) {
resolve(res.data);
},
})
})
}
调用身份证OCR识别之前需要先获取 access_token
//获取access_token
getToken(){
return new Promise((resolve,reject)=>{
let appKey = 'xxxxx';
let secretKey = 'xxxxx';
let url = `https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=${appKey}&client_secret=${secretKey}`;
wx.request({
url: url,
method:'POST',
dataType:'json',
header:{
'content-type': 'application/json; charset-UTF-8'
},
success(res){
resolve(res);
},
fail(err){
reject(err);
}
})
})
},
识别身份证
//识别图片
ocrCard(data){
return new Promise((resolve,reject)=>{
this.getToken().then(res=>{
let token = res.data.access_token
let url = `https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic?access_token=${token}`;
wx.request({
url: url,
method:'POST',
header:{
'Content-Type': 'application/x-www-form-urlencoded'
},
data:{
image:data,
id_card_side:'front'
},
success(res){
resolve(res);
},
fail(err){
reject(err);
}
})
})
})
}
上面就是照片选择到身份证OCR识别的整个过程;关于 access_token 也可以在页面加载的时候获取一次,然后将 access_token 缓存在本地,这样每次获取的时候需要先判断 access_token 是否过期;
对于拍照的照片,有些时候我们可能需要对其进行裁剪;
1、跳转到拍照页面
gotophoto(){
wx.navigateTo({
url: '/pages/photo/photo'
})
}
2、拍照页面
<camera type="2d" device-position="back" resolution="high" style="width: 100%; height: 100vh;">
<cover-view>
<!-- 拍照后的回显图片,必须在裁剪蒙层上面,不然不显示 -->
<cover-image wx:if="{{showPic}}" src="{{image}}"></cover-image>
<!-- 拍照蒙层,按照这个裁剪 -->
<cover-image src="http://print.jiaynet.cn/icons/zhezhao.png"></cover-image>
</cover-view>
<!-- 拍照按钮 -->
<cover-view style="color: #fff; width: 100%; position: fixed; left:0; bottom: 40rpx;">
<cover-view bindtap="takePhotoAction" style="width: 100%; text-align: center;">拍照</cover-view>
</cover-view>
</camera>
<!-- 这里的宽高一定不要忘记设置 -->
<canvas style='width:{{width}}px; height:{{height}}px; opacity: 0;' canvas-id="mycanvas"></canvas>
3、拍照
data: {
width:0,//设备宽度
height:0,//设备高度
image:'',
showPic:false
},
takePhotoAction(){
let that = this;
let ctx = wx.createCameraContext();
ctx.takePhoto({
quality:'high',
success(res){
that.loadTempImagePath(res.tempImagePath)
}
})
},
//剪切图片
loadTempImagePath(path){
let that = this;
//获取设备宽高信息
wx.getSystemInfo({
success: (res) => {
that.setData({
width:res.screenWidth,
height:res.screenHeight
})
let imgX = 0.1*that.data.width;
let imgY = 0.25*that.data.height;
let imgWidth = 0.8*that.data.width;
let imgHeight = 0.25*that.data.height;
//获取图片信息
wx.getImageInfo({
src: path,
success(res){
const canvas = wx.createCanvasContext('mycanvas', that);
//将图片放到画布上
canvas.drawImage(path,0,0,that.data.width,that.data.height);
//截取图片
canvas.draw(false,setTimeout(()=>{
wx.canvasToTempFilePath({
canvasId: 'mycanvas',
x: 50, //画布x轴起点
y: 200, //画布y轴起点
width: imgWidth, //画布宽度
height: imgHeight, //画布高度
destWidth: imgWidth, //输出图片宽度
destHeight: imgHeight, //输出图片高度
success(res){
that.setData({
image:res.tempFilePath,
showPic:true
})
}
})
}),1000)
}
})
},
})
}
这里的重点是对截图框位置的计算,可以根据自己的需求来设计宽高;
4、由于 createCanvasContext 在 2.9.0 开始停止维护,官网推荐使用 Canvas 代替
//wxml
<camera type="2d" device-position="back" resolution="high" style="width: 100%; height: 100vh;">
<cover-view>
<!-- 拍照后的回显图片,必须在上面,不然不显示 -->
<cover-image style="position: absolute; top: 0; left: 0; width: 348px; height: auto;" wx:if="{{showPic}}" src="{{image}}"></cover-image>
<!-- 拍照蒙层,按照这个裁剪 -->
<cover-image src="http://print.jiaynet.cn/icons/zhezhao.png"></cover-image>
</cover-view>
<!-- 拍照按钮 -->
<cover-view style="color: #fff; width: 100%; position: fixed; left:0; bottom: 40rpx;">
<cover-view bindtap="takePhotoAction" style="width: 100%; text-align: center;">拍照</cover-view>
</cover-view>
</camera>
<!-- -->
<canvas type="2d" id="mycanvas"></canvas>
//js
takePhotoAction(){
let that = this;
let ctx = wx.createCameraContext();
ctx.takePhoto({
quality:'high',
success(res){
that.setData({
image:res.tempImagePath
})
wx.createSelectorQuery()
.select('#mycanvas')
.fields({
node: true,
size: true
}, (res) => {
const canvas = res.node
const ctx2 = canvas.getContext('2d');
that.init(ctx2, canvas)
})
.exec()
}
})
},
init(ctx, canvas) {
let img = canvas.createImage()
img.src = this.data.image;
img.onload = (e) => {
let c_x = img.width * 0.05
let c_w = img.width * 0.89
let c_y = img.height * 0.365
let c_h = img.height * 0.12
//截取图片指定部分并绘制到canvas
ctx.drawImage(img, c_x, c_y, c_w, c_h, 0, 0, 300, 300 * (c_h / c_w))//width固定为300,按比例计算出height
//将canvas内容保存为图片
wx.canvasToTempFilePath({
canvas: canvas,
// x: 50, //画布x轴起点
// y: 280, //画布y轴起点
width: 335, //画布宽度
height: 216, //画布高度
// destWidth: 335, //输出图片宽度
// destHeight: 216, //输出图片高度
fileType: 'png',
success: (res) => {
this.setData({
image:res.tempFilePath,
showPic:true
})
//将图片保存到本地相册
wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
})
},
fail: (res) => {
console.log(res)
}
})
}
img.onerror = (e) => {
console.error('err:', e)
}
}
由于使用 canvas 时的 drawImage 参数比较难理解,请参考:canvas的drawImage方法参数详解