uniapp 身份证识别 微信 百度 图片前端压缩 图片后端压缩
2021-03-15 16:25 会飞的雪鹿 阅读(464) 评论(0) 编辑 收藏 举报微信:
1 下面注释代码 HBuilder调试OK 发布微信调试失败 不知所以 2 var ocrUrl = "https://api.weixin.qq.com/cv/ocr/idcard?img_url=" + self.imgUrl + "&access_token=" + self.token; 3 wx.chooseImage({ 4 sourceType: ['camera'], // 可以指定来源是相册还是相机,默认二者都有 5 const tempFilePaths = res.tempFilePaths 6 wx.uploadFile({ 7 url: ocrUrl, 8 filePath: tempFilePaths[0], 9 name: 'img', 10 formData: { 11 contentType: 'image/png', 12 value: "", 13 }, 14 success(res) { 15 const data = JSON.parse(res.data); 16 if (data.errcode != 0) { 17 self.$api.alert("识别失败!"); 18 } 19 self.name = data.name; 20 self.idNo = data.id; 21 if (numberUtils.identityCodeValid(self.idNo.trim())) { 22 self.age = self.getAge(self.idNo.trim()); 23 } 24 if (data.gender == '男') { 25 self.current = 0; 26 } else { 27 self.current = 1; 28 } 29 }, 30 fail(res) { 31 self.$api.alert("识别失败!"); 32 }, 33 })
前端 转byte64 压缩 /components/image-tools/index.js
1 function getLocalFilePath(path) { 2 if (path.indexOf('_www') === 0 || path.indexOf('_doc') === 0 || path.indexOf('_documents') === 0 || path.indexOf('_downloads') === 0) { 3 return path 4 } 5 if (path.indexOf('file://') === 0) { 6 return path 7 } 8 if (path.indexOf('/storage/emulated/0/') === 0) { 9 return path 10 } 11 if (path.indexOf('/') === 0) { 12 var localFilePath = plus.io.convertAbsoluteFileSystem(path) 13 if (localFilePath !== path) { 14 return localFilePath 15 } else { 16 path = path.substr(1) 17 } 18 } 19 return '_www/' + path 20 } 21 22 var index = 0 23 function getNewFileId() { 24 return Date.now() + String(index++) 25 } 26 27 function biggerThan(v1, v2) { 28 var v1Array = v1.split('.') 29 var v2Array = v2.split('.') 30 var update = false 31 for (var index = 0; index < v2Array.length; index++) { 32 var diff = v1Array[index] - v2Array[index] 33 if (diff !== 0) { 34 update = diff > 0 35 break 36 } 37 } 38 return update 39 } 40 41 export function pathToBase64(path) { 42 43 return new Promise(function(resolve, reject) { 44 if (typeof window === 'object' && 'document' in window) { 45 if (typeof FileReader === 'function') { 46 var xhr = new XMLHttpRequest() 47 xhr.open('GET', path, true) 48 xhr.responseType = 'blob' 49 xhr.onload = function() { 50 if (this.status === 200) { 51 let fileReader = new FileReader() 52 fileReader.onload = function(e) { 53 resolve(e.target.result) 54 } 55 fileReader.onerror = reject 56 fileReader.readAsDataURL(this.response) 57 } 58 } 59 xhr.onerror = reject 60 xhr.send() 61 return 62 } 63 var canvas = document.createElement('canvas') 64 var c2x = canvas.getContext('2d') 65 var img = new Image 66 img.onload = function() { 67 canvas.width = img.width 68 canvas.height = img.height 69 c2x.drawImage(img, 0, 0) 70 resolve(canvas.toDataURL()) 71 canvas.height = canvas.width = 0 72 } 73 img.onerror = reject 74 img.src = path 75 return 76 } 77 if (typeof plus === 'object') { 78 plus.io.resolveLocalFileSystemURL(getLocalFilePath(path), function(entry) { 79 entry.file(function(file) { 80 var fileReader = new plus.io.FileReader() 81 fileReader.onload = function(data) { 82 resolve(data.target.result) 83 } 84 fileReader.onerror = function(error) { 85 reject(error) 86 } 87 fileReader.readAsDataURL(file) 88 }, function(error) { 89 reject(error) 90 }) 91 }, function(error) { 92 reject(error) 93 }) 94 return 95 } 96 if (typeof wx === 'object' && wx.canIUse('getFileSystemManager')) { 97 wx.getFileSystemManager().readFile({ 98 filePath: path, 99 encoding: 'base64', 100 success: function(res) { 101 resolve('data:image/png;base64,' + res.data) 102 }, 103 fail: function(error) { 104 reject(error) 105 } 106 }) 107 return 108 } 109 reject(new Error('not support')) 110 }) 111 } 112 113 export function base64ToPath(base64) { 114 return new Promise(function(resolve, reject) { 115 if (typeof window === 'object' && 'document' in window) { 116 base64 = base64.split(',') 117 var type = base64[0].match(/:(.*?);/)[1] 118 var str = atob(base64[1]) 119 var n = str.length 120 var array = new Uint8Array(n) 121 while (n--) { 122 array[n] = str.charCodeAt(n) 123 } 124 return resolve((window.URL || window.webkitURL).createObjectURL(new Blob([array], { type: type }))) 125 } 126 var extName = base64.match(/data\:\S+\/(\S+);/) 127 if (extName) { 128 extName = extName[1] 129 } else { 130 reject(new Error('base64 error')) 131 } 132 var fileName = getNewFileId() + '.' + extName 133 if (typeof plus === 'object') { 134 var basePath = '_doc' 135 var dirPath = 'uniapp_temp' 136 var filePath = basePath + '/' + dirPath + '/' + fileName 137 if (!biggerThan(plus.os.name === 'Android' ? '1.9.9.80627' : '1.9.9.80472', plus.runtime.innerVersion)) { 138 plus.io.resolveLocalFileSystemURL(basePath, function(entry) { 139 entry.getDirectory(dirPath, { 140 create: true, 141 exclusive: false, 142 }, function(entry) { 143 entry.getFile(fileName, { 144 create: true, 145 exclusive: false, 146 }, function(entry) { 147 entry.createWriter(function(writer) { 148 writer.onwrite = function() { 149 resolve(filePath) 150 } 151 writer.onerror = reject 152 writer.seek(0) 153 writer.writeAsBinary(base64.replace(/^data:\S+\/\S+;base64,/, '')) 154 }, reject) 155 }, reject) 156 }, reject) 157 }, reject) 158 return 159 } 160 var bitmap = new plus.nativeObj.Bitmap(fileName) 161 bitmap.loadBase64Data(base64, function() { 162 bitmap.save(filePath, {}, function() { 163 bitmap.clear() 164 resolve(filePath) 165 }, function(error) { 166 bitmap.clear() 167 reject(error) 168 }) 169 }, function(error) { 170 bitmap.clear() 171 reject(error) 172 }) 173 return 174 } 175 if (typeof wx === 'object' && wx.canIUse('getFileSystemManager')) { 176 var filePath = wx.env.USER_DATA_PATH + '/' + fileName 177 wx.getFileSystemManager().writeFile({ 178 filePath: filePath, 179 data: base64.replace(/^data:\S+\/\S+;base64,/, ''), 180 encoding: 'base64', 181 success: function() { 182 resolve(filePath) 183 }, 184 fail: function(error) { 185 reject(error) 186 } 187 }) 188 return 189 } 190 reject(new Error('not support')) 191 }) 192 } 193 194 /** 195 * canvas压缩图片 196 * @param {参数obj} param 197 * @param {文件二进制流} param.file 必传 198 * @param {目标压缩大小} param.targetSize 不传初始赋值-1 199 * @param {输出图片宽度} param.width 不传初始赋值-1,等比缩放不用传高度 200 * @param {输出图片名称} param.fileName 不传初始赋值image 201 * @param {压缩图片程度} param.quality 不传初始赋值0.92。值范围0~1 202 * @param {回调函数} param.succ 必传 203 */ 204 export function pressImg(param){ 205 //如果没有回调函数就不执行 206 if(param && param.succ){ 207 //如果file没定义返回null 208 if(param.file == undefined) return param.succ(null); 209 //给参数附初始值 210 param.targetSize = param.hasOwnProperty("targetSize") ? param.targetSize : -1; 211 param.width = param.hasOwnProperty("width") ? param.width : -1; 212 param.fileName = param.hasOwnProperty("fileName") ? param.fileName: "image"; 213 param.quality = param.hasOwnProperty("quality") ? param.quality : 0.92; 214 var _this = this; 215 // 得到文件类型 216 // var fileType = param.file.type; 217 // // console.log(fileType) //image/jpeg 218 // if(fileType.indexOf("image") == -1){ 219 // console.log('请选择图片文件^_^'); 220 // return param.succ(null); 221 // } 222 // //如果当前size比目标size小,直接输出 223 // var size = param.file.size; 224 // if(param.targetSize > size){ 225 // return param.succ(param.file); 226 // } 227 // 读取file文件,得到的结果为base64位 228 // changeFileToBaseURL(param.file,function(base64){ 229 var fileType = "image"; 230 debugger; 231 var base64=param.file; 232 if(base64){ 233 var image = new Image(); 234 image.src = base64; 235 image.onload = function(){ 236 // 获得长宽比例 237 var scale = this.width / this.height; 238 // console.log(scale); 239 //创建一个canvas 240 var canvas = document.createElement('canvas'); 241 //获取上下文 242 var context = canvas.getContext('2d'); 243 //获取压缩后的图片宽度,如果width为-1,默认原图宽度 244 canvas.width = param.width == -1 ? this.width : param.width; 245 //获取压缩后的图片高度,如果width为-1,默认原图高度 246 canvas.height = param.width == -1 ? this.height : parseInt(param.width / scale); 247 //把图片绘制到canvas上面 248 context.drawImage(image, 0, 0, canvas.width, canvas.height); 249 //压缩图片,获取到新的base64Url 250 var newImageData = canvas.toDataURL(fileType,param.quality); 251 //将base64转化成文件流 252 // var resultFile = dataURLtoFile(newImageData,param.fileName); 253 // //判断如果targetSize有限制且压缩后的图片大小比目标大小大,就弹出错误 254 // if(param.targetSize != -1 && param.targetSize < resultFile.size){ 255 // console.log("图片上传尺寸太大,请重新上传^_^"); 256 // param.succ(null); 257 // }else{ 258 // //返回文件流 259 // param.succ(resultFile); 260 // } 261 param.succ(newImageData); 262 } 263 } 264 // }); 265 } 266 } 267 268 /** 269 * 将base64转换为文件 270 * @param {baseURL} dataurl 271 * @param {文件名称} filename 272 * @return {文件二进制流} 273 */ 274 function dataURLtoFile(dataurl, filename) { 275 var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], 276 bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); 277 while(n--){ 278 u8arr[n] = bstr.charCodeAt(n); 279 } 280 return new File([u8arr], filename, {type:mime}); 281 } 282 283 /** 284 * @param {二进制文件流} file 285 * @param {回调函数,返回base64} fn 286 */ 287 function changeFileToBaseURL(file,fn){ 288 // 创建读取文件对象 289 var fileReader = new FileReader(); 290 //如果file没定义返回null 291 if(file == undefined) return fn(null); 292 // 读取file文件,得到的结果为base64位 293 fileReader.readAsDataURL(file); 294 fileReader.onload = function(){ 295 // 把读取到的base64 296 var imgBase64Data = this.result; 297 fn(imgBase64Data); 298 } 299 }
1 引入工具 index.js 2 import { 3 pathToBase64, 4 base64ToPath, 5 pressImg 6 } from '@/components/image-tools/index.js' 7 8 uni.chooseImage({ 9 count: 1, // 默认9 10 sizeType: ['compressed'], // 可以指定是原图还是压缩图,默认二者都有 11 sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有 12 type: 'file', 13 success(res) { 14 debugger; 15 const tempFilePaths = res.tempFilePaths; 16 var that = res.tempFilePaths[0]; 17 // 地址转成Base64 18 pathToBase64(res.tempFilePaths[0]) 19 .then(base64 => { 20 //Base64 进行10倍压缩返回 Base64 21 pressImg({ 22 file: base64, 23 targetSize: 2 * 1024 * 1024, 24 quality: 0.1, 25 width: 600, 26 succ: function(resultFile) { 27 //如果不是null就是压缩成功 28 if (resultFile) { 29 //TODO 30 self.$api.request.post('/OCRIdCard/getIdCard', JSON.stringify(resultFile), function(res) { 31 if (res && res.code == "0" && res.data) { 32 const data = res.data; 33 self.name = data.words_result.姓名.words; 34 self.idNo = data.words_result.公民身份号码.words; 35 if (numberUtils.identityCodeValid(self.idNo)) { 36 self.age = self.getAge(self.idNo); 37 } 38 if (data.words_result.性别.words == '男') { 39 self.current = 0; 40 } else { 41 self.current = 1; 42 } 43 } else { 44 if (res.data) 45 self.$api.alert("识别失败!" + res.data); 46 else 47 self.$api.alert("识别失败!"); 48 } 49 50 }, function(res) { 51 uni.showToast({ 52 icon: 'none', 53 title: '未连接到服务,请联系管理员' + JSON.stringify(res), 54 }); 55 }, function() { 56 57 uni.hideLoading(); 58 }); 59 } 60 } 61 }) 62 });
java调百度api 工具类
引入两个包 一个Json 用 一个 压缩用
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20160810</version>
</dependency>
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.8</version>
</dependency>
package XXXXXXX; import java.awt.image.BufferedImage; import java.io.*; import java.math.BigDecimal; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.util.Base64; import java.util.List; import java.util.Map; import net.coobird.thumbnailator.Thumbnails; import org.json.JSONObject; import javax.imageio.ImageIO; public class BaiDuCardIdentification { public static String getIdCardMessage(String accessToken,String imgByte64) { // 请求url String url = "https://aip.baidubce.com/rest/2.0/ocr/v1/idcard"; try { imgByte64=imgByte64.replaceAll("data:image/(.*);base64,",""); byte[] imgData= commpressPicCycle(Base64.getDecoder().decode(imgByte64), 300, 0.5f); String imgStr = Base64Util.encode((byte[])imgData); String imgParam = URLEncoder.encode(imgStr, "UTF-8"); String param = "id_card_side=" + "front" + "&image=" + imgParam; // 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。 String result = HttpUtil.post(url, accessToken, param); System.out.println(result); return result; } catch (Exception e) { return "身份证识别次数没有了,请联系管理员"; } } public static String getAuth(String ak, String sk) { // 获取token地址 String authHost = "https://aip.baidubce.com/oauth/2.0/token?"; String getAccessTokenUrl = authHost // 1. grant_type为固定参数 + "grant_type=client_credentials" // 2. 官网获取的 API Key + "&client_id=" + ak // 3. 官网获取的 Secret Key + "&client_secret=" + sk; try { URL realUrl = new URL(getAccessTokenUrl); // 打开和URL之间的连接 HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection(); connection.setRequestMethod("GET");//设置请求方式 connection.connect();//发送url // 获取所有响应头字段 Map<String, List<String>> map = connection.getHeaderFields(); // 遍历所有的响应头字段 for (String key : map.keySet()) { System.err.println(key + "--->" + map.get(key)); } // 定义 BufferedReader输入流来读取URL的响应 BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); String result = ""; String line; while ((line = in.readLine()) != null) { result += line; } /** * 返回结果示例 */ JSONObject jsonObject = new JSONObject(result); String access_token = jsonObject.getString("access_token"); return access_token; } catch (Exception e) { return "获取token失败"; } } /** * * @param bytes 原图片字节数组 * @param desFileSize 指定图片大小,单位 kb * @param accuracy 精度,递归压缩的比率,建议小于0.9 * @return */ public static byte[] commpressPicCycle(byte[] bytes, long desFileSize, double accuracy) throws IOException { // 获取目标图片 // File imgFile = new File(desPath); // long fileSize = imgFile.length(); long fileSize = bytes.length; System.out.println("=====fileSize======== "+fileSize); // 判断图片大小是否小于指定图片大小 if(fileSize <= desFileSize * 1024){ return bytes; } //计算宽高 BufferedImage bim = ImageIO.read(new ByteArrayInputStream(bytes)); int imgWidth = bim.getWidth(); System.out.println(imgWidth+"====imgWidth====="); int imgHeight = bim.getHeight(); int desWidth = new BigDecimal(imgWidth).multiply( new BigDecimal(accuracy)).intValue(); System.out.println(desWidth+"====desWidth====="); int desHeight = new BigDecimal(imgHeight).multiply( new BigDecimal(accuracy)).intValue(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); //字节输出流(写入到内存) Thumbnails.of(new ByteArrayInputStream(bytes)).size(desWidth, desHeight).outputQuality(accuracy).toOutputStream(baos); //如果不满足要求,递归直至满足要求 return commpressPicCycle(baos.toByteArray(), desFileSize, accuracy); } }
1 @RequestMapping(value = "/getIdCard", method = RequestMethod.POST) 2 @WithoutAuthentication 3 public Result getIdCard(@RequestBody Object file){ 4 5 Result result = new Result(); 6 String auth = BaiDuCardIdentification.getAuth("client_id","client_secret");//获取access_token 7 //识别身份证信息 是要传入的两个参数 一个是access_token 另一个是文件的路径 8 String idcard = BaiDuCardIdentification.getIdCardMessage(auth, file.toString()); 9 JSONObject parse = JSONObject.parseObject(idcard); //将百度返回给我们的身份证信息 转换为json对象 10 String idcard_number_type = parse.get("idcard_number_type").toString();//获取idcard_number_type判断身份证是否合法 11 12 if (idcard.contains("edit_tool")) {//如果你的身份证图片被修改过 会返回这个字段 值为哪一个软件编辑过 13 result.setCode("300"); 14 result.setData("身份证被"+parse.get("edit_tool").toString()+"编辑过,请重新上传"); 15 return result; 16 } 17 if (parse.get("image_status").toString().equals("non_idcard")) {//判断你上传的这张图片是否是个身份证图片 18 result.setCode("300"); 19 result.setData("身份证不合格,请上传身份证照片面图片"); 20 return result; 21 } 22 if (idcard_number_type.equals("1")) {//只有idcard_number_type值为1的时候是合格的 其他的均为不合格 23 result.setCode("0"); 24 result.setData(parse); 25 return result; 26 27 } 28 //身份证不合格的就返回它的错误码 可以到官方文档查看具体的错误类型 29 result.setCode("200"); 30 result.setData("身份证不合法错误码为:"+idcard_number_type); 31 return result; 32 33 }