【湖南步联科技身份证】 身份证读取与酒店收银系统源码整合———未来之窗行业应用跨平台架构

 一、html5

<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><script type="text/javascript" src="http://51.onelink.ynwlzc.net/o2o/tpl/Merchant/static/js/jquery.min.js"></script><style type="text/css">html {height: 100%;width: 100%;}#readCard {width: 90px;margin: 10px;}#output {width: 500px;height: 200px;}</style></head><body><h1>读身份证示例-湖南步联科技身份证
</h1> <h1>未来之窗星链-推进器测试
</h1><br><input type="button" id="getReader" value="列出设备" style="margin:10px" onclick="getReader();" /><select id="readerList" style="width:250px;margin:10px"></select><!-- 读卡参数<input type="text" id="readParam" value='{"portType": 5}' size="25" style="margin:10px" > --><br/><input type="button" id="readCard" value="读卡" onclick="startReadCard();" /><input type="checkbox" id="autoReadCard" value="autoRead"  >自动读卡<br>阅读次数:<input type="text" id="totalReadCount" name="Num" value="100" size="7">成功次数<input type="text" id="SuccessTimes" value="0" size="7">失败次数<input type="text" id="FailTimes" value="0" size="7">所用时间<input type="text" id="TimeExpand" value="0" size="7">成功率<input type="text" id="Rate" value="0%" size="5">平均耗时<input type="text" id="AvgTime" value="0" size="5"><br>开始时间<input type="text" id="StartTime" value="" size="25">完成时间<input type="text" id="EndTime" value="" size="25">单次用时<input type="text" id="ReadTime" value="111" size="25"><table border="1" cellpadding="0" cellspacing="2" bordercolor="#3333FF"><tr><td><div align="right">姓名:</div></td><td><input name="text_name" type="text" id="text_name" size="20"/></td><td><div align="right">性别代码:</div></td><td><input name="text_genderid" type="text" id="text_genderid" size="5"/></td><td><div align="right">民族代码:</div></td><td><input name="text_nationid" type="text" id="text_nationid" size="5"/></td><td><div align="right">出生日期:</div></td><td><input name="text_birthdate" type="text" id="text_birthdate" size="20"/></td></tr><tr><td><div align="right">身份证号码:</div></td><td><input name="text_idnumber" type="text" id="text_idnumber" size="20"/></td><td><div align="right">签发机关:</div></td><td><input name="text_signorgan" type="text" id="text_signorgan" size="20"/></td><td><div align="right">起始有效期:</div></td><td><input name="text_beginterm" type="text" id="text_beginterm" size="20"/></td><td><div align="right">终止有效期:</div></td><td><input name="text_endterm" type="text" id="text_endterm" size="20"/></td></tr><tr><td><div align="right">住址:</div></td><td colspan="5"><input name="text_address" type="text" id="text_address" size="82"/></td><td><div align="right">民族:</div></td><td><input name="text_nationid" type="text" id="text_nation" size="5"/></td></tr><tr><td height="43"><div align="right">照片编码:</div></td><td colspan="7"><textarea name="text_photobase64" cols="80" rows="5" id="text_photobase64"></textarea></td><td><img name="PhotoDisplay" id="PhotoDisplay" style="width:102px; height:126px;"/></td></tr></table><br/><textarea id="output"></textarea><br/></body>
</html><script type="text/javascript" >var baseUrl = "http://127.0.0.1:6045"
$(document).ready(function(){//解决IE浏览器不支持console,报错未定义问题window.console = window.console || (function () {var c ={};c.log = c.warn = c.debug = c.info = c.error = c.time = c.dir = c.profile= c.clear = c.exception = c.trace = c.assert = function(){};return c;})();
//    alert(location.host)
//    if(location.host){
//        baseUrl = location.protocol + "//" + location.host;
//    }console.log("baseurl "+ baseUrl);});function fixInt(val){if(val<10)return "0"+val;elsereturn val;
}function fmtDate(date){return date.getFullYear()+"-"+fixInt(date.getMonth()+1)+"-"+fixInt(date.getDate())+" "+fixInt(date.getHours())+":"+fixInt(date.getMinutes())+":"+fixInt(date.getSeconds())+":"+fixInt(date.getMilliseconds());
}function clearForm() {$("#output").text("");$("#text_name").val("");$("#text_genderid").val("");$("#text_nationid").val("");$("#text_birthdate").val("");$("#text_address").val("");$("#text_idnumber").val("");$("#text_signorgan").val("");$("#text_beginterm").val("");$("#text_endterm").val("");}function getReader(){$.ajax({type: "get",dataType: "json", timeout:10000,crossDomain: true,url: baseUrl + "/getCardReaderList",success: function(resultInfo) {$("#output").text(JSON.stringify(resultInfo));var list = document.getElementById("readerList");for(var i = list.options.length-1; i >= 0; i--){list.remove(i);}var strArray = resultInfo;for(var i = 0; i < resultInfo.length; i++){var newOption = document.createElement("option");newOption.setAttribute("version", strArray[i].version);newOption.setAttribute("index", strArray[i].index);newOption.appendChild(document.createTextNode(strArray[i].version));list.appendChild(newOption);}},error: function(jqXHR, textStatus, errorThrown) {console.error("getReader request error  ", textStatus, errorThrown );$("#output").text("getReader error status "+ textStatus+" errorThrown "  +errorThrown)}});
}
function parseCardWzxx(wzxx) {var result = {};result['xm'] = wzxx.substr(0, 15);result['xbdm'] = wzxx.substr(15, 1);result['mzdm'] = wzxx.substr(16, 2);result['csrq'] = wzxx.substr(18, 8);result['dzmc'] = wzxx.substr(26, 35);result['gmsfhm'] = wzxx.substr(61, 18);result['qfjgmc'] = wzxx.substr(79, 15);result['qfjgmc'] = wzxx.substr(79, 15);result['yxqqsrq'] = wzxx.substr(94, 8);result['yxqjzrq'] = wzxx.substr(102, 8);result['zjlxbs'] = wzxx.substr(124, 1);switch (result['xbdm']) {case '1': result['xbmc'] = '男'; break;case '2': result['xbmc'] = '女'; break;default: result['xbmc'] = '未知';}if (result['zjlxbs'] == 'J'){result['txzhm'] = wzxx.substr(110, 9);result['qfcs'] = wzxx.substr(119, 2);}switch (result['mzdm']) {case '01': result['mzmc'] = '汉'; break;case '02': result['mzmc'] = '蒙古'; break;case '03': result['mzmc'] = '回'; break;case '04': result['mzmc'] = '藏'; break;case '05': result['mzmc'] = '维吾尔'; break;case '06': result['mzmc'] = '苗'; break;case '07': result['mzmc'] = '彝'; break;case '08': result['mzmc'] = '壮'; break;case '09': result['mzmc'] = '布依'; break;case '10': result['mzmc'] = '朝鲜'; break;case '11': result['mzmc'] = '满'; break;case '12': result['mzmc'] = '侗'; break;case '13': result['mzmc'] = '瑶'; break;case '14': result['mzmc'] = '白'; break;case '15': result['mzmc'] = '土家'; break;case '16': result['mzmc'] = '哈尼'; break;case '17': result['mzmc'] = '哈萨克'; break;case '18': result['mzmc'] = '傣'; break;case '19': result['mzmc'] = '黎'; break;case '20': result['mzmc'] = '傈僳'; break;case '21': result['mzmc'] = '佤'; break;case '22': result['mzmc'] = '畲'; break;case '23': result['mzmc'] = '高山'; break;case '24': result['mzmc'] = '拉祜'; break;case '25': result['mzmc'] = '水'; break;case '26': result['mzmc'] = '东乡'; break;case '27': result['mzmc'] = '纳西'; break;case '28': result['mzmc'] = '景颇'; break;case '29': result['mzmc'] = '柯尔克孜'; break;case '30': result['mzmc'] = '土'; break;case '31': result['mzmc'] = '达翰尔'; break;case '32': result['mzmc'] = '仫佬'; break;case '33': result['mzmc'] = '羌'; break;case '34': result['mzmc'] = '布朗'; break;case '35': result['mzmc'] = '撒拉'; break;case '36': result['mzmc'] = '毛南'; break;case '37': result['mzmc'] = '仡佬'; break;case '38': result['mzmc'] = '锡伯'; break;case '39': result['mzmc'] = '阿昌'; break;case '40': result['mzmc'] = '普米'; break;case '41': result['mzmc'] = '塔吉克'; break;case '42': result['mzmc'] = '怒'; break;case '43': result['mzmc'] = '乌孜别克'; break;case '44': result['mzmc'] = '俄罗斯'; break;case '45': result['mzmc'] = '鄂温克'; break;case '46': result['mzmc'] = '德昂'; break;case '47': result['mzmc'] = '保安'; break;case '48': result['mzmc'] = '裕固'; break;case '49': result['mzmc'] = '京'; break;case '50': result['mzmc'] = '塔塔尔'; break;case '51': result['mzmc'] = '独龙'; break;case '52': result['mzmc'] = '鄂伦春'; break;case '53': result['mzmc'] = '赫哲'; break;case '54': result['mzmc'] = '门巴'; break;case '55': result['mzmc'] = '珞巴'; break;case '56': result['mzmc'] = '基诺'; break;case '59': result['mzmc'] = '穿青人'; break;case '60': result['mzmc'] = '革家人'; break;case '97': result['mzmc'] = '其它'; break;case '98': result['mzmc'] = '入籍'; break;case '99': result['mzmc'] = '其它'; break;default: result['mzmc'] = '';}return result;
}
var totalStartTime;
var totalReadCount;
var SuccessTimes = 0;
var FailTimes = 0;
var totalUsedTime = 0;
function startReadCard(){totalStartTime = new Date();totalReadCount = $("#totalReadCount").val();SuccessTimes = 0;FailTimes = 0;totalUsedTime = 0;readCard();
}function readCard(){   clearForm();var startTime = new Date();$("#StartTime").val(fmtDate(startTime));$("#readCard").attr("disabled", "disabled");var readerIndex = $("#readerList").find("option:selected").attr("index");console.info("read card", readerIndex)$.ajax({type: "get",dataType: "json", timeout:10000,url: baseUrl + "/readIDCard?index="+readerIndex,success: function(resultInfo) {console.info("readIDCard ", resultInfo, status);$("#output").text(JSON.stringify(resultInfo));if( resultInfo.result === 0 ){var textInfo = resultInfo.wzInfo;$("#text_name").val(textInfo.substr(0,15).trim());$("#text_genderid").val(textInfo.substr(15,1).trim());$("#text_nationid").val(textInfo.substr(16,2).trim());$("#text_birthdate").val(textInfo.substr(18,8).trim());$("#text_address").val(textInfo.substr(26,35).trim());$("#text_idnumber").val(textInfo.substr(61,18).trim());$("#text_signorgan").val(textInfo.substr(79,15).trim());$("#text_beginterm").val(textInfo.substr(94,8).trim());$("#text_endterm").val(textInfo.substr(102,8).trim());var wzObj = parseCardWzxx(textInfo);$("#text_nation").val(wzObj.mzmc);console.info("read card success", wzObj) ;$.ajax({type: "get",dataType: "json", timeout:10000,url:baseUrl +"/wltUnpack?wlt="+resultInfo.zpWlt+"&format=bmp",success:function(response){if(response['result'] === 0){var imageBase64 = response['image'];$("#text_photobase64").val(imageBase64);document.all['PhotoDisplay'].src = 'data:image/bmp;base64,' + imageBase64;}else{alert("unpack error " + response['result']);}},complete: function(XMLHttpRequest, textStatus) {}});} var endTime = new Date();$("#EndTime").val(fmtDate(endTime));var usedTime = endTime.getTime()-startTime.getTime();$("#ReadTime").val(usedTime + "ms");if ( $('#autoReadCard').is(":checked") && totalReadCount--> 0){self.setTimeout("readCard()", 1000);totalUsedTime +=  usedTime;$("#TimeExpand").val(totalUsedTime + "ms");if(resultInfo.result == 0){++SuccessTimes; }else{++FailTimes;}$("#SuccessTimes").val(SuccessTimes);$("#FailTimes").val(FailTimes);$("#Rate").val(SuccessTimes*100/(SuccessTimes+FailTimes) + "%");$("#AvgTime").val(totalUsedTime/(SuccessTimes+FailTimes) + "ms");}else{$("#readCard").removeAttr("disabled");}},complete: function(XMLHttpRequest, textStatus) {
//            alert("cloudReadCard/appId complete");console.info("complete");},error: function(jqXHR, textStatus, errorThrown) {console.error("read card request error  ", textStatus, errorThrown );$("#output").text("read card error status "+ textStatus+" errorThrown "  +errorThrown)$("#readCard").removeAttr("disabled");}});
}</script>

二、JAVA

import com.bland.IDReader;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.Base64;import java.io.*;public class demo{static public String race_table[][] ={{"01","汉族"},//   GB/T 3304-1991","Han","HA{"02","蒙古族"},//   GB/T 3304-1991","Mongol","MG{"03","回族"},//   GB/T 3304-1991","Hui","HU{"04","藏族"},//   GB/T 3304-1991","Zang","ZA{"05","维吾尔族"},//   GB/T 3304-1991","Uygur","uG{"06","苗族"},//   GB/T 3304-1991","Miao","MH{"07","彝族"},//   GB/T 3304-1991","Yi","YI{"08","壮族"},//   GB/T 3304-1991","Zhuang","ZH{"09","布依族"},//   GB/T 3304-1991","Buyei","BY{"10","朝鲜族"},//   GB/T 3304-1991","Chosen","cs{"11","满族"},//   GB/T 3304-1991","Man","MA{"12","侗族"},//   GB/T 3304-1991","Dong","DO{"13","瑶族"},//   GB/T 3304-1991","Yao","YA{"14","白族"},//   GB/T 3304-1991","Bai","BA{"15","土家族"},//   GB/T 3304-1991","Tujia","TJ{"16","哈尼族"},//   GB/T 3304-1991","Hani","HN{"17","哈萨克族"},//   GB/T 3304-1991","Kazak","KZ{"18","傣族"},//   GB/T 3304-1991","Dai","DA{"19","黎族"},//   GB/T 3304-1991","Li","LI{"20","傈僳族"},//   GB/T 3304-1991","Lisu","LS{"21","佤族"},//   GB/T 3304-1991","Va","VA{"22","畲族"},//   GB/T 3304-1991","She","SH{"23","高山族"},//   GB/T 3304-1991","Gaoshan","Gs{"24","拉枯族"},//   GB/T 3304-1991","Lahu","LH{"25","水族"},//   GB/T 3304-1991","Sui","su{"26","东乡族"},//   GB/T 3304-1991","Dongxiang","DX{"27","纳西族"},//   GB/T 3304-1991","Naxi","NX{"28","景颇族"},//   GB/T 3304-1991","Jingpo","JP{"29","柯尔克孜族"},//   GB/T 3304-1991","Kirgiz","KG{"30","土族"},//   GB/T 3304-1991","Tu","TU{"31","达斡尔族"},//   GB/T 3304-1991","Daur","DU{"32","仫佬族"},//   GB/T 3304-1991","Mulao","ML{"33","羌族"},//   GB/T 3304-1991","Qiang","QI{"34","布朗族"},//   GB/T 3304-1991","Blang","BL{"35","撒拉族"},//   GB/T 3304-1991","Salar","SL{"36","毛南族"},//   GB/T 3304-1991","Maonan","MN{"37","仡佬族"},//   GB/T 3304-1991","Gelao","GL{"38","锡伯族"},//   GB/T 3304-1991","Xibe","XB{"39","阿昌族"},//   GB/T 3304-1991","Achang","AC{"40","普米族"},//   GB/T 3304-1991","Pumi","PM{"41","塔吉克族"},//   GB/T 3304-1991","Tajik","TA{"42","怒族"},//   GB/T 3304-1991","Nu","NU{"43","乌孜别克族"},//   GB/T 3304-1991","Uzbek","Uz{"44","俄罗斯族"},//   GB/T 3304-1991","Russ","RS{"45","鄂温克族"},//   GB/T 3304-1991","Ewenki","EW{"46","德昂族"},//   GB/T 3304-1991","Deang","DE{"47","保安族"},//   GB/T 3304-1991","Bonan","BN{"48","裕固族"},//   GB/T 3304-1991","Yugur","YG{"49","京族"},//   GB/T 3304-1991","Gin","GI{"50","塔塔尔族"},//   GB/T 3304-1991","Tatar","TT{"51","独龙族"},//   GB/T 3304-1991","Derung","DR{"52","鄂伦春族"},//   GB/T 3304-1991","Oroqen","OR{"53","赫哲族"},//   GB/T 3304-1991","Hezhen","HZ{"54","门巴族"},//   GB/T 3304-1991","Monba","MB{"55","珞巴族"},//   GB/T 3304-1991","Lhoba","LB{"56","基诺族"},//   GB/T 3304-1991","Jino","JN{"",""}};/*** 将民族代码,转换成文本* @param code* @return*/public static String GetRace(String code) {int i;for (i = 0; i < race_table.length; i++) {if (race_table[i][0].compareTo(code) == 0) {return race_table[i][1];}}return "其它";}/*** 显示身份证信息* @param text 文本* @param image 照片*/public static void ViewInfo(String text,byte[] image) {System.out.println(text);try{File imgFile = new File("image.jpg"); FileOutputStream writer = new FileOutputStream(imgFile); writer.write(image); writer.close(); }catch (Exception e){e.printStackTrace(); }}/*** 解析SN* @param str JSON 格式字符串* @return 返回错误或成功信息*/public static int ParseSN(String str) {byte[] img;String info = "";try {JSONObject jsondata = new JSONObject(str);if(jsondata.has("errorMsg")) {//System.out.println(jsondata.getString("errorMsg"));return -1;}if( !jsondata.has("data") ) {return -1;}JSONObject content = jsondata.getJSONObject("data");System.out.println("SAM ID: " + content.getString("samid"));if(content.has("sn")) {System.out.println("SN: " + content.getString("sn"));}}catch (Exception e) {e.printStackTrace(); return -1;}return 0;}/*** 解析身份证读卡结果* @param str JSON 格式字符串* @return 返回错误或成功信息*/public static String ParseIDInfo(String str) {byte[] img;String info = "";try {JSONObject jsondata = new JSONObject(str);if(jsondata.getString("function").compareTo("readcard") != 0) {return "";//不是读卡消息,直接返回}if(jsondata.has("errorMsg")) {System.out.println(jsondata.getString("errorMsg"));return jsondata.getString("errorMsg");}if( !jsondata.has("data") ) {return "";}JSONObject content = jsondata.getJSONObject("data");if(content.getString("type").compareTo("I") == 0) { info = "外国人永久居留证";}else if(content.getString("type").compareTo("J") == 0) { info = "港澳台居住证";}else if(content.getString("type").compareTo(" ") == 0) { info = "居民身份证";}else  {info = "未知";}info = info + "\r\n姓名:" + content.getString("name");info = info + "\r\n身份证号:" + content.getString("number");String gender;if(content.getInt("gender") == 1) {gender = "男";}else if (content.getInt("gender") == 2){gender = "女";}else {gender = "未知";}info = info + "\r\n性别: " + gender;if(content.getString("type").compareTo(" ") == 0) { //只有身份证有民族信息info = info + "\r\n民族: " + GetRace(content.getString("race"));}info = info + "\r\n生日: " + content.getString("birthday");if(content.getString("type").compareTo("I") != 0 ) { //外国人永久居留证没有住址信息info = info + "\r\n住址: " + content.getString("address");}info = info + "\r\n签发机关: " + content.getString("issuer");info = info + "\r\n有效期限: " + content.getString("valied") + "-" + content.getString("expire");if(content.getString("type").compareTo("I") == 0) { //外国人永久居留证info = info + "\r\n中文名称: " + content.getString("cn_name");info = info + "\r\n版本: " + content.getString("version");info = info + "\r\n国籍: " + content.getString("nation");}else if(content.getString("type").compareTo("J") == 0) { //港澳台居住证info = info + "\r\n通行证号码: " + content.getString("pass_number");info = info + "\r\n签发次数: " + content.getString("issue_count");}info = info + "\r\n";img = Base64.getDecoder().decode(content.getString("photo"));ViewInfo(info,img);return "读卡成功!";}catch (Exception e) {e.printStackTrace(); return e.getMessage();}}/*** 解析银行卡读卡结果* @param str JSON 格式字符串* @return 返回错误或成功信息*/public static String ParseBankInfo(String str) {byte[] img;String info = "";try {JSONObject jsondata = new JSONObject(str);if(jsondata.has("errorMsg")) {System.out.println(jsondata.getString("errorMsg"));return jsondata.getString("errorMsg");}if( !jsondata.has("data") ) {return "";}JSONObject content = jsondata.getJSONObject("data");info = info + "\r\n银行卡号:" + content.getString("number");info = info + "\r\n有效期截止: " + content.getString("expire");info = info + "\r\n持卡人:" + content.getString("owner");info = info + "\r\n持卡人证件号码: " + content.getString("owner_id");info = info + "\r\n";System.out.println(info);return "读卡成功!";}catch (Exception e) {e.printStackTrace(); return e.getMessage();}}/*** 解析读卡结果的返回值* @param str JSON 格式字符串* @return 返回读卡结果的返回值*/public static int GetRetValue(String str) {try {JSONObject jsondata = new JSONObject(str);if(jsondata.has("ret")) {return jsondata.getInt("ret");}else {return -1;}}catch (Exception e) {e.printStackTrace(); return -1;}}public static void main(String [] args) {String systemType = System.getProperty("os.name");   String systemArch = System.getProperty("os.arch");   IDReader reader = new IDReader();System.out.println("System Type: " + systemType + ", " + systemArch);//提供一个可读写的目录,用于初始化过程中读写配置,解压调用库文件。初始化只能调用一次。reader.Init("./res");System.out.println("demo start!");try{while(true) {Thread.sleep(100);String result = reader.WebSocketAPI("{\"module\":\"idcard\",\"msgid\":\"0\",\"function\":\"getsam\"}");if(ParseSN(result) == 0) {break;}}}catch (Exception e){e.printStackTrace(); }try{while(true) {String result;result = reader.WebSocketAPI("{\"module\":\"idcard\",\"msgid\":\"0\",\"function\":\"readcard\"}");if( GetRetValue(result) == 0) {ParseIDInfo(result);Thread.sleep(1000);continue;}result = reader.WebSocketAPI("{\"module\":\"iccard\",\"msgid\":\"0\",\"function\":\"iso14443a_find\"}");if( GetRetValue(result) == 0) {//读银行卡号码result = reader.WebSocketAPI("{\"module\":\"iccard\",\"msgid\":\"0\",\"function\":\"pboc_read\"}");ParseBankInfo(result);Thread.sleep(1000);continue;}Thread.sleep(100);}}catch (Exception e){e.printStackTrace(); }}
}

三、PYTHON

# -*- coding: utf-8 -*-
# import urllib2
import urllib.request
import json
import timerace = ["","汉族","蒙古族","回族","藏族","维吾尔族","苗族","彝族","壮族","布依族","朝鲜族","满族","侗族","瑶族","白族","土家族","哈尼族","哈萨克族","傣族","黎族","傈僳族","佤族","畲族","高山族","拉枯族","水族","东乡族","纳西族","景颇族","柯尔克孜族","土族","达斡尔族","仫佬族","羌族","布朗族","撒拉族","毛南族","仡佬族","锡伯族","阿昌族","普米族","塔吉克族","怒族","乌孜别克族","俄罗斯族","鄂温克族","德昂族","保安族","裕固族","京族","塔塔尔族","独龙族","鄂伦春族","赫哲族","门巴族","珞巴族" ,"基诺族"]
gender = ["未知","男","女","其他"]while 1:time.sleep(1)url = "http://127.0.0.1:7846/api/readCard?utf8=1"response = urllib.request.urlopen(url)page_html = response.read()#print(page_html)result = json.loads(page_html)if result["resultFlag"] == "0":print("读卡成功:\n")print("身份证号码:"+result["resultContent"]["idNum"])print("姓名:"+result["resultContent"]["name"])print("性别:"+gender[int(result["resultContent"]["gender"])])print("民族:"+race[int(result["resultContent"]["nation"])])print("地址:"+result["resultContent"]["address"])print("生日:"+result["resultContent"]["birthday"])print("有效期: "+result["resultContent"]["effectDate"] + "-" + result["resultContent"]["expireDate"] )print("签发机关: "+result["resultContent"]["issueOrg"])continueurl = "http://127.0.0.1:7846/readBankCard"response = urllib.request.urlopen(url)page_html = response.read()#print(page_html)result = json.loads(page_html)if result["result"] == 0 :print("读卡成功:\n")print("银行卡号码:"+result["number"])print("有效期截止:"+result["expire"])print("持卡人:"+result["owner"])print("持卡人证件号码:"+result["owner_id"])

四、VB

Public Class Form1Dim port As reader_serviceLib.sdt = New reader_serviceLib.sdt()Dim card As reader_serviceLib.cardPrivate Sub refreshButton()Dim ret As Integerret = port.opened()If ret = 0 ThenbtOpen.Enabled = TruebtReadCard.Enabled = FalsebtReadBank.Enabled = FalsebtOpen.Text = "打开"ElsebtOpen.Enabled = TruebtReadCard.Enabled = TruebtReadBank.Enabled = TruebtOpen.Text = "关闭"If ret > 1000 ThenTextStatus.Text = "已打开USB端口" & retElseTextStatus.Text = "已打开串口COM" & retEnd IfTextSAMID.Text = port.samid()End IfEnd SubPrivate Sub btReadCard_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btReadCard.ClickDim ret As Integerret = port.find()If ret <> &H9F ThenTextStatus.Text = "找卡失败!"Exit SubEnd Ifret = port.select()If ret <> &H90 ThenTextStatus.Text = "选卡失败!"Exit SubEnd IfTextCardSN.Text = port.cardSN(0)card = port.readcard(0)If card.name = "" ThenTextStatus.Text = "读卡失败!"Exit SubEnd IfTextName.Text = card.nameTextAddress.Text = card.addressTextBirthday.Text = card.birthdayTextGender.Text = card.genderTextIssuer.Text = card.issuerTextRace.Text = card.raceTextNumber.Text = card.numberTextExpired.Text = card.valied & "-" & card.expirePictureBox1.ImageLocation = card.image_pathEnd SubPrivate Sub btOpen_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btOpen.ClickDim ret As IntegerIf ComboPortList.Text = "USB" Thenret = port.open(1001, 115200)ElseIf ComboPortList.Text.StartsWith("COM") Thenret = port.open(Integer.Parse(ComboPortList.Text.Substring(3)), 115200)Elseret = port.open(0, 0)End IfIf ret <> &H90 ThenTextStatus.Text = "端口打开失败!"Exit SubEnd IfCall refreshButton()End SubPrivate Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.LoadrefreshButton()End SubPrivate Sub btReadBank_Click(sender As Object, e As EventArgs) Handles btReadBank.ClickDim uid As reader_serviceLib.iso14443a_uidDim obj()Dim ret As Integerobj = port.iso14443a_find(4)If obj.Length = 0 ThenTextStatus.Text = "找卡失败!"' 必须要退出 ISO14443A 模式,否则下次无法读取身份证Call port.iso14443a_mode_exit()Exit SubEnd Ifuid = obj(0)ret = port.iso14443a_select(uid.text, uid.sak)If ret <> &H90 Then' 必须要退出 ISO14443A 模式,否则下次无法读取身份证Call port.iso14443a_mode_exit()Call MsgBox("选卡失败!")Exit SubEnd If'参数0代表读身份证,参数1代表读银行卡card = port.readcard(1)If card.number = "" Then' 必须要退出 ISO14443A 模式,否则下次无法读取身份证Call port.iso14443a_mode_exit()Call MsgBox("读卡失败!")Exit SubEnd IfCall MsgBox("银行卡号:" & card.number & ";有效期:" & card.expire & ";持卡人:" & card.name)' 必须要退出 ISO14443A 模式,否则下次无法读取身份证Call port.iso14443a_mode_exit()End Sub
End Class

五、安卓

package com.example.demo;import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.usb.UsbManager;
import android.os.Bundle;import com.bland.IDReader;
import com.bland.TpNfc;
import com.google.android.material.snackbar.Snackbar;import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Message;
import android.os.Handler;
import android.view.View;
import android.app.PendingIntent;
import android.content.Context;
import android.hardware.usb.UsbDevice;
import android.widget.Toast;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
import android.content.Intent;
import android.content.IntentFilter;
import com.example.demo.databinding.ActivityMainBinding;import java.util.HashMap;import android.view.Menu;
import android.view.MenuItem;
import android.nfc.tech.NfcB;import org.json.JSONArray;
import org.json.JSONObject;
import 	android.provider.Settings;
import android.content.Context;
import android.nfc.Tag;
import android.nfc.NfcAdapter;
import android.util.Log;
import java.util.HashMap;
import android.util.Base64;
import android.widget.ImageView;
import android.widget.TextView;public class MainActivity extends AppCompatActivity {//用于身份证解码先关变量public String race_table[][] ={{"01","汉族"},//   GB/T 3304-1991","Han","HA{"02","蒙古族"},//   GB/T 3304-1991","Mongol","MG{"03","回族"},//   GB/T 3304-1991","Hui","HU{"04","藏族"},//   GB/T 3304-1991","Zang","ZA{"05","维吾尔族"},//   GB/T 3304-1991","Uygur","uG{"06","苗族"},//   GB/T 3304-1991","Miao","MH{"07","彝族"},//   GB/T 3304-1991","Yi","YI{"08","壮族"},//   GB/T 3304-1991","Zhuang","ZH{"09","布依族"},//   GB/T 3304-1991","Buyei","BY{"10","朝鲜族"},//   GB/T 3304-1991","Chosen","cs{"11","满族"},//   GB/T 3304-1991","Man","MA{"12","侗族"},//   GB/T 3304-1991","Dong","DO{"13","瑶族"},//   GB/T 3304-1991","Yao","YA{"14","白族"},//   GB/T 3304-1991","Bai","BA{"15","土家族"},//   GB/T 3304-1991","Tujia","TJ{"16","哈尼族"},//   GB/T 3304-1991","Hani","HN{"17","哈萨克族"},//   GB/T 3304-1991","Kazak","KZ{"18","傣族"},//   GB/T 3304-1991","Dai","DA{"19","黎族"},//   GB/T 3304-1991","Li","LI{"20","傈僳族"},//   GB/T 3304-1991","Lisu","LS{"21","佤族"},//   GB/T 3304-1991","Va","VA{"22","畲族"},//   GB/T 3304-1991","She","SH{"23","高山族"},//   GB/T 3304-1991","Gaoshan","Gs{"24","拉枯族"},//   GB/T 3304-1991","Lahu","LH{"25","水族"},//   GB/T 3304-1991","Sui","su{"26","东乡族"},//   GB/T 3304-1991","Dongxiang","DX{"27","纳西族"},//   GB/T 3304-1991","Naxi","NX{"28","景颇族"},//   GB/T 3304-1991","Jingpo","JP{"29","柯尔克孜族"},//   GB/T 3304-1991","Kirgiz","KG{"30","土族"},//   GB/T 3304-1991","Tu","TU{"31","达斡尔族"},//   GB/T 3304-1991","Daur","DU{"32","仫佬族"},//   GB/T 3304-1991","Mulao","ML{"33","羌族"},//   GB/T 3304-1991","Qiang","QI{"34","布朗族"},//   GB/T 3304-1991","Blang","BL{"35","撒拉族"},//   GB/T 3304-1991","Salar","SL{"36","毛南族"},//   GB/T 3304-1991","Maonan","MN{"37","仡佬族"},//   GB/T 3304-1991","Gelao","GL{"38","锡伯族"},//   GB/T 3304-1991","Xibe","XB{"39","阿昌族"},//   GB/T 3304-1991","Achang","AC{"40","普米族"},//   GB/T 3304-1991","Pumi","PM{"41","塔吉克族"},//   GB/T 3304-1991","Tajik","TA{"42","怒族"},//   GB/T 3304-1991","Nu","NU{"43","乌孜别克族"},//   GB/T 3304-1991","Uzbek","Uz{"44","俄罗斯族"},//   GB/T 3304-1991","Russ","RS{"45","鄂温克族"},//   GB/T 3304-1991","Ewenki","EW{"46","德昂族"},//   GB/T 3304-1991","Deang","DE{"47","保安族"},//   GB/T 3304-1991","Bonan","BN{"48","裕固族"},//   GB/T 3304-1991","Yugur","YG{"49","京族"},//   GB/T 3304-1991","Gin","GI{"50","塔塔尔族"},//   GB/T 3304-1991","Tatar","TT{"51","独龙族"},//   GB/T 3304-1991","Derung","DR{"52","鄂伦春族"},//   GB/T 3304-1991","Oroqen","OR{"53","赫哲族"},//   GB/T 3304-1991","Hezhen","HZ{"54","门巴族"},//   GB/T 3304-1991","Monba","MB{"55","珞巴族"},//   GB/T 3304-1991","Lhoba","LB{"56","基诺族"},//   GB/T 3304-1991","Jino","JN{"",""}};private static final int SDK_NFC_FLAG = 3;private static final int SDK_READER_FLAG = 4;private static final int SDK_DEVICE_FLAG = 5;private static final int SDK_CLIENT_FLAG = 6;private static final int SDK_ICCARD_FLAG = 7;private static final int SDK_BANKCARD_FLAG = 8;//用于 OTG 阅读器相关变量public IDReader reader;public UsbManager usbManager;private static final String ACTION_USB_PERMISSION = "com.android.usb.USB_PERMISSION";private boolean id_card_exist = false;      // 标记上一次读卡时,身份证是否存在private String samid = "";                      // 标记阅读器是否连接,以及SAM ID是多少private String last_idcard_text = "";           // 最近一次身份证读卡信息,方便判断身份证是否变化private String last_iccard_text = "";           // 最近一次Mifare one读卡数据信息private String last_iccard_uid = "";           // 最近一次Mifare one 读卡UID信息private int last_iccard_sak = 0;           // 最近一次Mifare one 读卡SAK信息//用于手机本机 NFC 相关变量public TpNfc tpnfc;NfcAdapter mNfcAdapter;PendingIntent pIntent;//其他变量private AppBarConfiguration appBarConfiguration;private ActivityMainBinding binding;/*** 将民族代码,转换成文本* @param code* @return*/public String GetRace(String code) {int i;for (i = 0; i < race_table.length; i++) {if (race_table[i][0].compareTo(code) == 0) {return race_table[i][1];}}return "其它";}/*** 在 UI 上显示身份证信息* @param text 文本* @param image 照片*/void ViewInfo(String text,Bitmap image) {TextView tv = (TextView) findViewById(R.id.textview_first);ImageView iv = (ImageView) findViewById(R.id.imageView);tv.setText(text.toCharArray(), 0, text.toCharArray().length);iv.setImageBitmap(image);}/*** 解析身份证读卡结果* @param str JSON 格式字符串* @return 返回错误或成功信息*/String ParseInfo(String str) {Bitmap decodedByte = null;String info = "";try {JSONObject jsondata = new JSONObject(str);if(jsondata.getString("function").compareTo("readcard") != 0) {return "";//不是读卡消息,直接返回}if(jsondata.has("errorMsg")) {ViewInfo(info,decodedByte);  //卡片已拿走或其他错误,清空信息return jsondata.getString("errorMsg");}if( !jsondata.has("data") ) {//异常情况,不应该出现,清空信息ViewInfo(info,decodedByte);return "";}JSONObject content = jsondata.getJSONObject("data");if(content.getString("type").compareTo("I") == 0) {info = "2017版外国人永久居留证";}else if(content.getString("type").compareTo("Y") == 0) {info = "新版外国人永久居留证";}else if(content.getString("type").compareTo("J") == 0) {info = "港澳台居住证";}else if(content.getString("type").compareTo(" ") == 0) {info = "居民身份证";}else  {info = "未知";}info = info + "\r\n姓名:" + content.getString("name");info = info + "\r\n身份证号:" + content.getString("number");String gender;if(content.getInt("gender") == 1) {gender = "男";}else if (content.getInt("gender") == 2){gender = "女";}else {gender = "未知";}info = info + "\r\n性别: " + gender;if(content.getString("type").compareTo(" ") == 0) {//只有身份证有民族信息info = info + "\r\n民族: " + GetRace(content.getString("race"));}info = info + "\r\n生日: " + content.getString("birthday");if(content.getString("type").compareTo("I") != 0 ) {//外国人永久居留证没有住址信息info = info + "\r\n住址: " + content.getString("address");}info = info + "\r\n签发机关: " + content.getString("issuer");info = info + "\r\n有效期限: " + content.getString("valied") + "-" + content.getString("expire");if(content.getString("type").compareTo("I") == 0) {//2017版外国人永久居留证info = info + "\r\n中文名称: " + content.getString("cn_name");info = info + "\r\n版本: " + content.getString("version");info = info + "\r\n国籍: " + content.getString("nation");}else if(content.getString("type").compareTo("Y") == 0) {//新版外国人永久居留证info = info + "\r\n中文名称: " + content.getString("cn_name");info = info + "\r\n换证次数: " + content.getString("renewal_count");info = info + "\r\n关联号码: " + content.getString("relational_number");info = info + "\r\n国籍: " + content.getString("nation");}else if(content.getString("type").compareTo("J") == 0) {//港澳台居住证info = info + "\r\n通行证号码: " + content.getString("pass_number");info = info + "\r\n签发次数: " + content.getString("issue_count");}byte[] img = Base64.decode(content.getString("photo"),Base64.DEFAULT);decodedByte = BitmapFactory.decodeByteArray(img, 0, img.length);ViewInfo(info,decodedByte);return "读卡成功!";}catch (Exception e) {return e.getMessage();}}/*** 处理身份证阅读消息,或者 OTG 阅读器插入拔出消息*/@SuppressLint("HandlerLeak")private Handler mHandler = new Handler(){@Overridepublic  void handleMessage(Message msg) {String err = "";switch (msg.what) {case SDK_NFC_FLAG: {err = ParseInfo((String)msg.obj);break;}case SDK_READER_FLAG: {err = ParseInfo((String)msg.obj);break;}case SDK_DEVICE_FLAG:{if(samid == "" ) {err = "阅读器已拔出!";}else {err = "阅读器已连接:" + samid;}break;}case SDK_CLIENT_FLAG: {ViewInfo((String)msg.obj,null);break;}case SDK_ICCARD_FLAG: {if(last_iccard_uid != "") {ViewInfo("uid: " + last_iccard_uid + "\r\ndata: " + last_iccard_text, null);}else {ViewInfo("",null);}break;}case SDK_BANKCARD_FLAG: {if(last_iccard_uid != "") {ViewInfo("uid: " + last_iccard_uid + "\r\n" + (String)msg.obj, null);}else {ViewInfo("",null);}break;}}if (err != "") {Snackbar.make(findViewById(R.id.fab), err, Snackbar.LENGTH_LONG).setAction("Action", null).show();}}};/*** 申请 USB OTG 阅读器访问权限* @param usbManager* @return*/public int UsbPermission(UsbManager usbManager) {//单独申请USB权限PendingIntent permissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE);HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();for (UsbDevice usbDevice : deviceList.values()) {if( reader.CompareReaderID(usbDevice.getVendorId(),usbDevice.getProductId()) ) {if(!usbManager.hasPermission(usbDevice)) {usbManager.requestPermission(usbDevice, permissionIntent);}else {}Log.e("id_reader","Reader found!");break;}else {}Log.e("id_reader","Name: " + usbDevice.getManufacturerName() + " " + usbDevice.getProductName() + ", VID: " + usbDevice.getVendorId() + ",PID: " + usbDevice.getProductId());}return 0;}/*** 发送消息到 UI* @param str*/public void SendMsg(String str,int type) {Message msg = new Message();msg = new Message();if(mHandler != null) {msg.what = type;msg.obj = str;mHandler.sendMessage(msg);}}/*** 发送 OTG 阅读器连接或拔出的消息到 UI* @param samid*/public void SendDeviceMsg(String samid) {SendMsg(samid,SDK_DEVICE_FLAG);}/*** 发送身份证读卡结果消息到 UI* @param result 身份证读卡结果,JSON格式* @param type*/public void SendCardInfoMsg(String result,int type) {//tpnfc.SetLastRead(result);SendMsg(result,type);}/*** 判断 OTG 阅读器身份证读卡结果是否有变化,以决定是否需要发送消息到 UI* @param result* @return 返回身份证是否存在于OTG 阅读器*/public boolean OnIDCardResult(String result) {try {boolean cur_exist;JSONObject jsondata = new JSONObject(result);if(jsondata.getInt("ret") != 0 ) {if (jsondata.getInt("ret") == 2) {//阅读器设备状态改变,变为不存在,发送通知消息samid = "";SendDeviceMsg(samid);}last_idcard_text = "";cur_exist = false;}else {cur_exist = true;}if(jsondata.has("data")) {JSONObject data = jsondata.getJSONObject("data");if(data.has("text")) {String cur_text = data.getString("text");if (cur_text.compareTo(last_idcard_text) != 0) {//卡片信息发生改变,发送通知消息id_card_exist = true;last_idcard_text = cur_text;SendCardInfoMsg(result, SDK_READER_FLAG);return id_card_exist;}}}if(cur_exist != id_card_exist) {//卡片状态发生改变,发送通知消息id_card_exist = cur_exist;SendCardInfoMsg(result, SDK_READER_FLAG);return id_card_exist;}}catch (Exception e) {id_card_exist = false;}return id_card_exist;}/*** 判断 OTG Mifare one 读卡结果是否有变化,以决定是否需要发送消息到 UI* @param result* @return 返回Mifare one 卡是否存在*/public boolean OnICCardResult(String result) {try {JSONObject jsondata = new JSONObject(result);if(jsondata.getInt("ret") != 0 ) {if (jsondata.getInt("ret") == 2) {//阅读器设备状态改变,变为不存在,发送通知消息samid = "";SendDeviceMsg(samid);}last_iccard_text = "";last_iccard_sak = 0;}String cmd = jsondata.getString("function");if(jsondata.has("data")) {JSONObject data = jsondata.getJSONObject("data");if( cmd.compareTo("iso14443a_find") == 0) {//处理找卡结果JSONArray uid = data.getJSONArray("uid");if(uid.length()>0) {last_iccard_uid = uid.getJSONObject(0).getString("text");last_iccard_sak = uid.getJSONObject(0).getInt("sak");return true;}else {}}else if(cmd.compareTo("pboc_read") == 0 && data.has("number") ) {if(last_iccard_text.compareTo(data.getString("number")) !=0 ) {last_iccard_text = data.getString("number");String bankInfo = "银行卡号:"+data.getString("number") + "\r\n";bankInfo += "有效期截止:" + data.getString("expire") + "\r\n";bankInfo += "持卡人:" + data.getString("owner") + "\r\n";bankInfo += "持卡人证件号码:" + data.getString("owner_id") + "\r\n";SendCardInfoMsg(bankInfo, SDK_BANKCARD_FLAG);}return true;}else if( data.has("hex") ){//处理读到的数据if(last_iccard_text.compareTo(data.getString("hex")) !=0 ) {reader.WebSocketAPI("{\"module\":\"common\",\"msgid\":\"0\",\"function\":\"beep\",\"data\":{\"length\":200}}");last_iccard_text = data.getString("hex");SendCardInfoMsg(result, SDK_ICCARD_FLAG);}return true;}}if(last_iccard_text != "" || last_iccard_uid != "") {//卡片状态发生改变,发送通知消息last_iccard_uid = "";last_iccard_text = "";last_iccard_sak = 0;SendCardInfoMsg(result, SDK_ICCARD_FLAG);}return false;}catch (Exception e) {return false;}}/*** 清除读卡结果,并发送消息到 UI*/public void ClearReaderResult() {if( samid.compareTo("") != 0 ){samid = "";SendDeviceMsg(samid);}if(id_card_exist) {id_card_exist = false;SendCardInfoMsg("{\"module\":\"idcard\",\"msgid\":\"0\",\"function\":\"readcard\",\"errorMsg\":\"设备不存在\",\"ret\":2}", SDK_READER_FLAG);}last_idcard_text = "";}/*** 读取 OTG 阅读器的 SAM ID,并返回 OTG 阅读器是否存在* @return 返回 OTG 阅读器是否存在*/public boolean CheckSamID() {String result;JSONObject jsondata;try {if(samid == "" ) {result = reader.WebSocketAPI("{\"module\":\"idcard\",\"msgid\":\"0\",\"function\":\"getsam\"}");jsondata = new JSONObject(result);if(jsondata.has("errorMsg") ) {if(jsondata.has("ret") && jsondata.getInt("ret") == 2) {//设备不存在}return false;}if(!jsondata.has("data") ) {return false;}JSONObject data = jsondata.getJSONObject("data");if(!data.has("samid") ) {return false;}samid = data.getString("samid");if(samid == "" ) {return false;}SendDeviceMsg(samid);}return true;}catch(Exception e) {return false;}}/*** 使用 OTG 阅读器读取身份证,处理读取结果并返回身份证是否存在* @return 返回身份证是否存在*/public boolean ReadIDCard() {try {if(!id_card_exist) {//还没有检测到卡片存在的情况下,可以先找卡和选卡。 这段代码不是必须,可以去掉,一样正常使用if( ! OnIDCardResult( reader.WebSocketAPI("{\"module\":\"idcard\",\"msgid\":\"0\",\"function\":\"findcard\"}") ) ){return false;}if( !OnIDCardResult( reader.WebSocketAPI("{\"module\":\"idcard\",\"msgid\":\"0\",\"function\":\"selectcard\"}") ) ) {return false;}}return OnIDCardResult( reader.WebSocketAPI("{\"module\":\"idcard\",\"msgid\":\"0\",\"function\":\"readcard\"}") );}catch(Exception e) {return false;}}/*** 使用 OTG 阅读器读取Mifare one卡* @return 返回Mifare one卡是否存在*/public boolean ReadICCard() {String cmd,pre_uid;if(id_card_exist) {//确认身份证卡片已存在的情况下,不读IC卡,避免冲突return false;}try {pre_uid = last_iccard_uid;if (!OnICCardResult(reader.WebSocketAPI("{\"module\":\"iccard\",\"msgid\":\"0\",\"function\":\"iso14443a_find\"}"))) {return false;}if( last_iccard_uid.compareTo(pre_uid) == 0) {//卡没有发生变化,不重复读了return true;}if((last_iccard_sak & 0x20) == 0x20 ) {//构造读取银行卡号码的指令cmd = "{\"module\":\"iccard\",\"msgid\":\"0\",\"function\":\"pboc_read\",\"data\": {\"uid\":\""+ last_iccard_uid + "\"} }";}else {//构造读取 IC 卡的第 0 个Block 的指令int type = 0x60;  //密钥A:0x60 , 密钥B:0x61String key = "FFFFFFFFFFFF";int block = 0;cmd = "{\"module\":\"iccard\",\"msgid\":\"0\",\"function\":\"mifare_read\",\"data\": {\"uid\":\""+ last_iccard_uid + "\",\"block\":"+block+",\"type\":"+ type + ",\"key\":\""+key+"\"} }";}return OnICCardResult( reader.WebSocketAPI(cmd) );}catch(Exception e) {return false;}}/*** OTG 阅读器读取身份证信息线程*/Runnable runnable = new Runnable() {@Overridepublic void run() {while(true) {int  msgid = 0;try {if( reader.Connected(usbManager) ) {// 使用串口转网口模块时, reader.Connected(usbManager) 改为 true,直接 if(true) {if(!CheckSamID()) {Thread.sleep(1000);continue;}if( ReadIDCard() || ReadICCard()) {Thread.sleep(100);continue;}Thread.sleep(100);}else {ClearReaderResult();Thread.sleep(200);continue;}}catch (Exception e) {String error = e.toString();Log.e("id_reader",error);}}}};/***  感应到身份证时触发该事件。实现手机本机 NFC 读身份证。* @param intent*/@Overrideprotected void onNewIntent(Intent intent){super.onNewIntent(intent);setIntent(intent);Tag tag = getIntent().getParcelableExtra(NfcAdapter.EXTRA_TAG);if(tag == null ) {return ;}//sendCardInfoMsg("{\"module\" : \"tpnfc\",\"function\" : \"card\", \"data\": {\"id\":\"" + byte2hex(tag.getId()) + "\"},\"ret\":0}",SDK_NFC_FLAG);NfcB card = NfcB.get(tag);if(card == null ) {return;}try {card.connect();String result = tpnfc.LocalNfcRead(card);card.close();JSONObject content = new JSONObject(result);if(content.has("errorMsg")) {String error = content.getString("errorMsg");String s = new String(error.getBytes("ISO-8859-1"), "UTF-8");String info = "\nerror: " + s + "\n";}SendCardInfoMsg(result,SDK_NFC_FLAG);}catch (java.io.IOException e){String result = "{\"module\" : \"idcard\",\"function\" : \"readcard\",\"errorMsg\":\"" + e.getMessage() + "\",\"errorNo\":34, \"server_error_code\": 0 ,\"server_error_string\": \"\"}";SendCardInfoMsg(result,SDK_NFC_FLAG);}catch (Exception e){String result = "{\"module\" : \"idcard\",\"function\" : \"readcard\",\"errorMsg\":\"" + e.getMessage() + "\",\"errorNo\":34, \"server_error_code\": 0 ,\"server_error_string\": \"\"}";SendCardInfoMsg(result,SDK_NFC_FLAG);}}/*** 初始化手机本机 NFC 读身份证的相关变量和事件* @param path 提供可读写的路径,用于保存会话信息*/public void InitNfc(String path){TpNfc.Init(path);tpnfc = new TpNfc();mNfcAdapter = NfcAdapter.getDefaultAdapter(this);if (null == mNfcAdapter) {Toast.makeText(this, "不支持NFC功能", Toast.LENGTH_SHORT).show();TpNfc.nfc_support = 0;} else if (!mNfcAdapter.isEnabled()) {TpNfc.nfc_support = 0;Intent intent = new Intent(Settings.ACTION_NFC_SETTINGS);// 根据包名打开对应的设置界面startActivity(intent);}else {TpNfc.nfc_support = 1;}pIntent = PendingIntent.getActivity(this, 0,//在Manifest里或者这里设置当前activity启动模式,否则每次向阳NFC事件,activity会重复创建// 当然也要按照具体情况来,你设置成singleTask也不是不行,new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),PendingIntent.FLAG_MUTABLE);}/*** 初始化 OTG 阅读器相关的变量、事件、权限等等* @param path 提供可读写的路径,用于保存配置*/public void InitReader(String path){IDReader.ServiceStart(path);reader = new IDReader();usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);UsbPermission(usbManager);new Thread(runnable).start();}/*** 修改手机本机 NFC 的相关设置*/@Overrideprotected void onResume() {super.onResume();if (mNfcAdapter != null) {//添加intent-filterIntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);IntentFilter tag = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);IntentFilter tech = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);IntentFilter[] filters = new IntentFilter[]{ndef, tag, tech};String[][] techList = new String[][]{new String[]{"android.nfc.tech.Ndef","android.nfc.tech.NfcA","android.nfc.tech.NfcB","android.nfc.tech.NfcF","android.nfc.tech.NfcV","android.nfc.tech.NdefFormatable","android.nfc.tech.MifareClassic","android.nfc.tech.MifareUltralight","android.nfc.tech.NfcBarcode"}};mNfcAdapter.enableForegroundDispatch(this, pIntent, filters, techList);}}@Overrideprotected void onPause() {super.onPause();if (mNfcAdapter != null) {mNfcAdapter.disableForegroundDispatch(this);}}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);binding = ActivityMainBinding.inflate(getLayoutInflater());setContentView(binding.getRoot());String path = getFilesDir().toString();InitNfc(path);InitReader(path);setSupportActionBar(binding.toolbar);NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build();NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);binding.fab.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {if(tpnfc == null ) {return ;}/*使用手机本机 NFC 阅读身份证时,需要先将手机与账号绑定。步骤如下:1. 官网注册账号2. 使用 tpnfc.SendBindRequest 向账号发送绑定请求3. 官网登录账号,接受绑定请求3. 调用 tpnfc.ClientInfo() 获取信息,判断是否绑定成功。4. 绑定成功功后,即可正常使用手机NFC读取身份证信息*/String info = "";String user = "18118742537"; //用户账号try {JSONObject jsondata = new JSONObject(tpnfc.ClientInfo());if (jsondata.has("secret") && jsondata.has("limit") && jsondata.has("expire")) {//已经绑定账号info = "NFC客户端\n有效期:" + jsondata.getString("expire") + "\n次数限制:" + jsondata.getInt("decode") + "/" + jsondata.getInt("limit");if(jsondata.getString("secret").compareTo("ok") != 0) {//客户端认证失败,需要解除绑定后,再重新绑定info += "\n密钥:密钥丢失,需要重新绑定";info += "\n解除绑定:" + ParseServerError(tpnfc.Unbind(jsondata.getString("id"), user)); //解除绑定}else {}} else {//还未绑定账号, 发送绑定请求, tpnfc.SendBindRequest 第一个参数为 客户端名称, 第二个参数是用户账号(手机号码)info += "发送绑定请求:";info += ParseServerError(tpnfc.SendBindRequest("测试NFC客户端", user));}}catch ( Exception e) {info = e.getMessage();}SendMsg(info,SDK_CLIENT_FLAG);}});}public String ParseServerError(String result) {String err = "";try {JSONObject ret = new JSONObject(result);if (ret.has("errorMsg")) {if (ret.getInt("errorNo") == 43) {err = "操作失败:" + ret.getString("server_error_string");} else {err = "操作失败:" + ret.getString("errorMsg");}} else {err = "操作成功!";}}catch (Exception e) {err = e.getMessage();}return err;}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.menu_main, menu);return true;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {// Handle action bar item clicks here. The action bar will// automatically handle clicks on the Home/Up button, so long// as you specify a parent activity in AndroidManifest.xml.int id = item.getItemId();//noinspection SimplifiableIfStatementif (id == R.id.action_settings) {//测试重启服务reader.ServiceStop();reader.ServiceStart(getFilesDir().toString());return true;}return super.onOptionsItemSelected(item);}@Overridepublic boolean onSupportNavigateUp() {NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);return NavigationUI.navigateUp(navController, appBarConfiguration)|| super.onSupportNavigateUp();}}

六、C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;namespace webapi_http
{public partial class Form1 : Form{public Form1(){InitializeComponent();}private void btReadCard_Click(object sender, EventArgs e){string result;string url = "http://127.0.0.1:7846/api/readCard?utf8=1";try{HttpWebRequest wbRequest = (HttpWebRequest)WebRequest.Create(url);wbRequest.Proxy = null;wbRequest.Method = "GET";HttpWebResponse wbResponse = (HttpWebResponse)wbRequest.GetResponse();using (Stream responseStream = wbResponse.GetResponseStream()){using (StreamReader sReader = new StreamReader(responseStream)){result = sReader.ReadToEnd();}}}catch (Exception ex){result = ex.Message;     //输出捕获到的异常,用OUT关键字输出}textResult.Text = result;}}
}

七、C

#include <stdio.h>
#include <sdtapi.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>#ifndef WIN32
#include <sys/time.h>
#include <sys/stat.h>
#include <dirent.h>void Sleep(unsigned int x)  
{ struct timespec xsleep; \xsleep.tv_sec = x / 1000; \xsleep.tv_nsec = (x - xsleep.tv_sec * 1000) * 1000 * 1000; \nanosleep(&xsleep, NULL); \
}
#else
#include <windows.h>
#include <winnls.h>#endif#include "bland.h"#ifndef WIN32
void print_com_list()//for linux
{struct dirent *pDirent;DIR *pDir;int i,index;struct stat st;char path[512] = {0};pDir = opendir("/sys/class/tty");if (pDir == NULL) {return ;}for (i=0,index=1;;i++) {pDirent = readdir(pDir);if(pDirent == NULL) {break;}snprintf(path,sizeof(path)-1,"/sys/class/tty/%s/device",pDirent->d_name);if (lstat(path, &st) < 0) {continue;}printf("COM%d: %s\n",index,path);index++;}closedir(pDir);
}//使用 UTF-8 字符编码
#define GetName			GetNameUtf8
#define GetGender		GetGenderUtf8
#define GetBirthday		GetBirthdayUtf8
#define GetAddress		GetAddressUtf8
#define GetRace			GetRaceUtf8
#define GetIDNum		GetIDNumUtf8
#define GetIssuer		GetIssuerUtf8
#define GetValidFrom	GetValidFromUtf8
#define GetExpireDate	GetExpireDateUtf8
#define GetPassNum		GetPassNumUtf8
#define GetIssueCount	GetIssueCountUtf8
#define GetNationCode	GetNationCodeUtf8
#define GetCnName		GetCnNameUtf8#endifvoid print_info2(char * text)
{char str[256] = {0};char str2[256] = {0};int ret,type;type = GetType(text);ret = GetName(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("name: %s\n",str);ret = GetGender(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("gender: %s\n",str);if(type == ' ') {//只有身份证有此项ret = GetRace(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("race: %s\n",str);}ret = GetBirthday(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("birthday: %s\n",str);if(type != 'I' && type != 'Y') {//外国人永久居留证没有此项ret = GetAddress(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("address: %s\n",str);}ret = GetIDNum(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("IDNum: %s\n",str);ret = GetIssuer(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("issuer: %s\n",str);ret = GetValidFrom(text,str,sizeof(str));if(ret < 0) {goto info_error;}ret = GetExpireDate(text,str2,sizeof(str2));if(ret < 0) {goto info_error;}printf("valid: %s-%s\n",str,str2);if(type == 'J') {ret = GetPassNum(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("passNum: %s\n",str);ret = GetIssueCount(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("IssueCount: %s\n",str);}else if(type == 'I' || type == 'Y') {ret = GetNationCode(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("nation: %s\n",str);ret = GetCnName(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("cnName: %s\n",str);if(type == 'I') {//2017版外国人永久居留证ret = GetCardVersion(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("version: %s\n",str);}else {ret = GetRelationalNum(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("relational number: %s\n",str);ret = GetRenewalCount(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("renewal count: %s\n",str);}}printf("\n");info_error:return ;
}unsigned int get_sector_num(unsigned int block_num)
{int sector;if (block_num < 128){sector = block_num / 4;}else{sector = ((block_num - 128) / 16) + 32;}return sector;
}#define MAX_UID_FIND	6//读取银行卡卡号等信息
int ReadBankCard(int iPort, ISO14443A_UID_T * card)
{int ret;char number[256] = {0};char info[sizeof(number)] = {0};ret = ReadPbocCardNumA(iPort,card->UID,card->UIDLen,number,info,sizeof(number));if(ret>0) {printf("Bank Card Number:\t%s\n",number);printf("Other Information:\t%s\n",info);return ret;}else {return -1;}
}//读取 Mifare IC卡
int ReadMifare(int iPort, ISO14443A_UID_T * card)
{int ret;unsigned int j,i;int max_block,sector;int type = 0x60; // 0x60 为密钥A 认证, 0x61 为密钥B认证unsigned char data[256][16] = {0};unsigned char key[6] = {0xff,0xff,0xff,0xff,0xff,0xff};//read card if(card->SAK == 0x18){max_block = 256;}else {max_block = 64;}for (i = 0, sector=-1 ;i< max_block;i++){if(get_sector_num(i) != sector ){//扇区发生变化,需要重新认证//需要先HALT一下卡片,必要的,但暂不清楚原因ISO14443A_Halt(iPort, 0);sector = get_sector_num(i);ret = MIFARE1_AuthBlock(iPort, card->UID, card->UIDLen, i, type, key, 0);if (ret != 0x90){printf("Mifare Auth block %d Failed!\n",i);return -1;}}ret = MIFARE1_ReadBlock(iPort, i, data[i], 0);if (ret != 0x90) {printf("Read block %d failed!\n",i);return -1;}}/* //write blockmemset(data,rand(),16);ISO14443A_Halt(iPort, 0);MIFARE1_AuthBlock(iPort, uid[0].UID, uid[0].UIDLen, 1, type, key, 0);ret = MIFARE1_WriteBlock(iPort,1,data,0);if(ret != 0x90) {printf("Write block 1 failed!\n");return -1;}*///for (i = 0;i< max_block && i<8;i++) //只显示一部分数据,否则内容太多刷屏了{for(j=0;j<16;j++) {if(j==8) {printf(" ");}printf("%02X ",data[i][j]);}printf("\n");}return max_block;
}static unsigned char passport_data[128*1024];
static unsigned char passport_photo[256*1024];void ReadPassport(int iPort,const char * pass_num, const char * birthday, const char * expire)
{int ret;FILE * fp;//读护照char auth[90] = {0};char MRZ[256];//生成认证码 authGetICAO9303AuthCode(pass_num,birthday,expire,auth);//读取护照ret = ReadICAO9303All(iPort,auth,passport_data,sizeof(passport_data));if(ret<=0) {return ;}ret = GetICAO9303MRZ(passport_data,MRZ,sizeof(MRZ));if(ret<0) {return ;}//读取护照/港澳通行证成功printf("MRZ: %s\n",MRZ);ret = GetICAO9303JpgData(passport_data,passport_photo,sizeof(passport_photo));if(ret>0) {fp = fopen("image.jpg","wb+");if(fp) {fwrite(passport_photo,1,ret,fp);fclose(fp);}}
}void ReadOtherCard(int iPort)
{int ret;unsigned int j,i,cnt = 0;ISO14443A_UID_T uid[MAX_UID_FIND];//find cardret = ISO14443A_FindCard(iPort,uid,MAX_UID_FIND,&cnt,0);if(ret != 0x90) {goto finished;}if(cnt <= 0) {goto finished;}for(i=0;i<cnt;i++) {	if(uid[i].SAK == 0x8) {printf("Mifare S50:\t");}else if(uid[i].SAK == 0x18) {printf("Mifare S70:\t");}else {printf("Unknow:\t");}for(j=0;j<uid[i].UIDLen;j++) {printf("%02X",uid[i].UID[j]);}printf("\n");}if(uid[0].SAK & 0x8) {//尝试作为 Mifare IC卡读取ret = ReadMifare(iPort,&uid[0]);if(ret>=0) {ISO14443A_Halt(iPort,0);SDT_ReaderBeep(iPort,100,0);Sleep(1000);}ISO14443A_ModeExit(iPort,0); //退出模式(短暂关闭天线),并Sleep一段时间,解决部分银行卡作为Mifare卡读过之后,就不能读取银行卡号的问题Sleep(200);}if(uid[0].SAK & 0x20) {//尝试作为银行卡读取ret = ReadBankCard(iPort,&uid[0]);if(ret>=0) {SDT_ReaderBeep(iPort,100,0);Sleep(1000);goto finished;}}if(uid[0].SAK & 0x20) {//尝试作为护照/港澳通行证读取ISO14443A_ModeExit(iPort,0);//  接口要求需要先退出type a模式Sleep(10);// 读取护照的参数需要通过OCR文字识别,获得护照(或港澳通行证)的号码,生日,过期时间, 并作为参数传入// 所以此处传入的 "C06765690", "131116", "191125" 只是示例, 需要根据实际情况修改ReadPassport(iPort,"C06765690","131116","191125");}finished:// 从 ISO14443A 模式切回 ISO14443B模式(读取身份证模式),这样可以继续读取身份证,还起到了重置 ISO14443A 类型卡片的作用ISO14443A_ModeExit(iPort,0);Sleep(50);
}int main(int argc, char * argv[])
{int port = 1001;int ret;unsigned char ManaInfo[4];unsigned char ManaMsg[8];unsigned char text[256];unsigned char image[1024];unsigned char finger[1024];unsigned char AppInfo[1024];unsigned char bmp[65536];unsigned int textLen,imageLen,fingerLen,AppInfoLen;unsigned int ID[4];char str[1024];FILE * fp;if(argc > 1) {port = atoi(argv[1]);}
#ifndef WIN32print_com_list();
#endifwhile(1) {ret = SDT_GetSAMStatus(port,1);if(ret != 0x90 ) {Sleep(200);continue;}
/*SDT.ResetSAM(port,1);Sleep(1000);continue;
*/ret = SDT_OpenPort(port);if(ret != 0x90 ) {Sleep(200);continue;}printf("reader detected!\n");ret = SDT_GetSAMID(port,(unsigned char *)ID,0);if(ret!= 0x90) {SDT_ClosePort(port);continue;}ret = SDT_GetSAMID(port,(unsigned char *)ID,0);if(ret!= 0x90) {SDT_ClosePort(port);continue;}printf("SAMID: %02d.%02d-%08d-%010d-%010d\n",ID[0]&0xffff,ID[0]>>16,ID[1],ID[2],ID[3]);ret = SDT_GetSAMIDToStr(port,str,0);if(ret!= 0x90) {SDT_ClosePort(port);continue;}printf("SAMID: %s\n",str);while(1) {ret = SDT_ReadBaseFPMsg(port,text,&textLen,image,&imageLen,finger,&fingerLen,0);if(ret == 0x90) {printf("read card success!(%d,%d,%d)\n",textLen,imageLen,fingerLen);goto success;}else if(ret < 0x21 ){break;}ret = SDT_StartFindIDCard(port,ManaInfo,0);if(ret == 0x9f) {printf("find card success!\n");}else  if(ret < 0x21 ){break;}else {//读取其他类型的卡片ReadOtherCard(port);Sleep(100);continue;}ret = SDT_SelectIDCard(port,ManaMsg,0);if(ret == 0x90) {printf("select card success!\n");}else  if(ret < 0x21 ){break;}else {printf("select failed!(ret=0x%02X)\n",ret);Sleep(1000);continue;}ret = SDT_ReadBaseFPMsg(port,text,&textLen,image,&imageLen,finger,&fingerLen,0);if(ret == 0x90) {printf("read card success!(%d,%d,%d)\n",textLen,imageLen,fingerLen);goto success;}else  if(ret < 0x21 ){break;}else  {printf("read card failed!(ret=0x%02X)\n",ret);// 读取护照的参数需要通过OCR文字识别,获得护照(或港澳通行证)的号码,生日,过期时间, 并作为参数传入// 所以此处传入的 "E18314949", "870623", "240615" 只是示例, 需要根据实际情况修改ReadPassport(port,"E18314949","870623","240615");//身份证读取失败了,尝试读取护照/港澳通行证Sleep(1000);continue;}success:AppInfoLen = 0;ret = SDT_ReadNewAppMsg(port,AppInfo,&AppInfoLen,0);if(ret == 0x90){printf("read address success!(%d)\n",AppInfoLen);}else {printf("no address!(0x%x)\n",ret);}ret = SDT_ReadBaseFPMsgToFile(port,"text.txt",&textLen,"image.wlt",&imageLen,"finger.bin",&fingerLen,0);print_info2((char*)text);ret = GetBmpData(image,bmp,sizeof(bmp));if(ret > 0 ) {fp = fopen("image.bmp","wb+");if(fp) {fwrite(bmp,1,ret,fp);fclose(fp);}}Sleep(1000);}printf("reader removed!\n");SDT_ClosePort(port);}return 0;
}

八、Delphi

object Form1: TForm1Left = 212Top = 147Width = 1740Height = 900Caption = #27493#32852#31185#25216' '#36523#20221#35777#38405#35835#28436#31034#31243#24207Color = clBtnFaceFont.Charset = DEFAULT_CHARSETFont.Color = clWindowTextFont.Height = -13Font.Name = 'MS Sans Serif'Font.Style = []OldCreateOrder = FalseOnCreate = OnCreatePixelsPerInch = 120TextHeight = 16object Label1: TLabelLeft = 16Top = 32Width = 48Height = 16Caption = #31471#21475#21495#65306endobject Label2: TLabelLeft = 16Top = 136Width = 36Height = 16Caption = #22995#21517#65306endobject Label3: TLabelLeft = 16Top = 176Width = 36Height = 16Caption = #24615#21035#65306endobject Label4: TLabelLeft = 184Top = 176Width = 36Height = 16Caption = #27665#26063#65306endobject Label5: TLabelLeft = 16Top = 208Width = 60Height = 16Caption = #20986#29983#26085#26399#65306endobject Label6: TLabelLeft = 16Top = 240Width = 36Height = 16Caption = #20303#22336#65306endobject Label7: TLabelLeft = 16Top = 328Width = 72Height = 16Caption = #36523#20221#35777#21495#30721#65306endobject Label8: TLabelLeft = 16Top = 368Width = 60Height = 16Caption = #31614#21457#26426#20851#65306endobject Label9: TLabelLeft = 16Top = 400Width = 60Height = 16Caption = #26377#25928#26399#38480#65306endobject Label10: TLabelLeft = 16Top = 72Width = 54Height = 16Caption = 'SAMID'#65306endobject Label11: TLabelLeft = 16Top = 104Width = 60Height = 16Caption = #21345#29255#24207#21495#65306endobject Image1: TImageLeft = 296Top = 104Width = 105Height = 105endobject txtName: TEditLeft = 136Top = 136Width = 137Height = 24ReadOnly = TrueTabOrder = 0endobject txtGender: TEditLeft = 136Top = 168Width = 41Height = 24ReadOnly = TrueTabOrder = 1endobject btRead: TButtonLeft = 392Top = 32Width = 75Height = 25Caption = #35835#21345TabOrder = 2OnClick = btReadClickendobject btOpen: TButtonLeft = 280Top = 32Width = 97Height = 25Caption = #25171#24320#31471#21475TabOrder = 3OnClick = btOpenClickendobject cbPort: TComboBoxLeft = 136Top = 32Width = 129Height = 24ItemHeight = 16TabOrder = 4Text = '0'endobject txtBirthday: TEditLeft = 136Top = 200Width = 137Height = 24ReadOnly = TrueTabOrder = 5endobject txtAddress: TEditLeft = 136Top = 232Width = 209Height = 24ReadOnly = TrueTabOrder = 6endobject txtNumber: TEditLeft = 136Top = 328Width = 209Height = 24ReadOnly = TrueTabOrder = 7endobject txtIssuer: TEditLeft = 136Top = 360Width = 209Height = 24ReadOnly = TrueTabOrder = 8endobject txtValid: TEditLeft = 136Top = 392Width = 209Height = 24ReadOnly = TrueTabOrder = 9endobject txtSAMID: TEditLeft = 136Top = 64Width = 241Height = 24ReadOnly = TrueTabOrder = 10endobject StatusBar1: TStatusBarLeft = 0Top = 834Width = 1722Height = 19Panels = <itemWidth = 250enditemWidth = 450end>endobject txtRace: TEditLeft = 232Top = 168Width = 41Height = 24ReadOnly = TrueTabOrder = 12endobject txtCardSn: TEditLeft = 136Top = 104Width = 137Height = 24ReadOnly = TrueTabOrder = 13end
end

九、阿雪技术观


拥抱开源与共享,见证科技进步奇迹,畅享人类幸福时光!

让我们积极投身于技术共享的浪潮中,不仅仅是作为受益者,更要成为贡献者。无论是分享自己的代码、撰写技术博客,还是参与开源项目的维护和改进,每一个小小的举动都可能成为推动技术进步的巨大力量

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1548632.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【CSS in Depth 2 精译_041】6.4 CSS 中的堆叠上下文与 z-index(上)

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一章 层叠、优先级与继承&#xff08;已完结&#xff09;第二章 相对单位&#xff08;已完结&#xff09;第三章 文档流与盒模型&#xff08;已完结&#xff09;第四章 Flexbox 布局&#xff08;已…

养猫久了才发现,宠物空气净化器才是真正除猫毛的神器

相信每个打工人都在期待这个国庆小长假吧&#xff0c;终于等到了&#xff01;这次我要把属于我的都夺回来&#xff01;刚好工资到手、小长假我有&#xff0c;只想往家里一躺什么也不想&#xff0c;唯一最想做的就是要在这个节假日里好好的陪一下我家猫咪&#xff0c;还有就是买…

关于LlamaIndex 的存储概念和代码基本实现

概念 LlamaIndex 提供了一个高级接口&#xff0c;用于提取、索引和查询外部数据。 在后台&#xff0c;LlamaIndex 还支持可插拔的存储组件&#xff0c;允许您自定义&#xff1a; Document stores 文档存储&#xff1a;存储摄取的文档&#xff08;即对象&#xff09;的位置&a…

cscode搭建vue项目

创建前安装环境 ctrlj弹出终端 window需要管理员运行并且授权 node -v # 显示版本号&#xff0c;说明 node 已经装好 npm -v # 显示版本号&#xff0c;说明 npm 可以使用 # 安装cnpm npm install -g cnpm --registryhttps://registry.npm.taobao.org cnpm -v # 显示版本号&a…

深度学习(三)——Springer特刊推荐

特刊征稿 01 期刊名称&#xff1a; MOBILE NETWORKS & APPLICATIONS 特刊名称&#xff1a;Resource Efficient Deep Learning for Computer Vision Applications 截止时间&#xff1a; 开放提交&#xff1a;2023年12月13日 提交截止日期&#xff1a;2024年10月30日 目标…

关于LlamaIndex 的几种索引方式介绍

每个索引的工作原理 本指南介绍每个索引如何与图表配合使用。 一些术语&#xff1a; Node&#xff1a;对应于 Document 中的一段文本。LlamaIndex 接收 Document 对象&#xff0c;并在内部将它们解析/分块为 Node 对象。Response Synthesis&#xff1a;我们的模块&#xff0…

【一文读懂】C#如何实现通用的排序功能

目录 通用排序功能 1.升序 2.降序 测试 1.测试代码 2.测试结果 本篇文章来分享一下C#如何实现通用的排序功能。在项目中经常会使用到排序的方法&#xff0c;那如何使排序方法更加通用呢&#xff1f;可以通过泛型&#xff0c;接口&#xff0c;委托来实现。 通用排序功能…

再也不用担心内容重复!在线伪原创工具,让创作更自由!

大家好&#xff0c;今天我们将讨论一个对网络写作非常有益的辅助工具——在线内容转换工具。不论您是需要更新您的博客&#xff0c;还是希望在社交平台上保持活跃&#xff0c;我们都频繁面临着迅速生成新内容的挑战。利用一个有效的工具来改写现有内容&#xff0c;可以极大地提…

机器学习笔记(李宏毅老师2021/2022课程)【更新中】

目录 前言 课程预览 第一讲 机器学习基本概念 前言 本文主要记录在听李宏毅老师的课时对应做的课堂笔记 课程&#xff1a; (强推)李宏毅2021/2022春机器学习课程_哔哩哔哩_bilibili 课程预览 机器学习找函数 &#xff08;找一个人类写不出来的复杂函数&#xff09; 课程侧…

Splashtop 自收购 Foxpass 以来新业务增长62%

2024年9月24日 加利福尼亚州库比蒂诺 Splashtop 在简化远程办公解决方案领域处于领先地位&#xff0c;今天宣布继去年收购 Foxpass 之后&#xff0c;新的 Foxpass 业务实现了62%的增长。Splashtop 的 Foxpass Cloud RADIUS 可确保企业 Wi-Fi 网络安全&#xff0c;防止未经授权…

PaddleOCR 表格识别,docker部署,cpu版本

前置环境 centeros7 docker 拉取镜像 docker pull registry.baidubce.com/paddlepaddle/paddle:2.6.1 参考&#xff1a;开始使用_飞桨-源于产业实践的开源深度学习平台 这里拉取的镜像并不能立马用&#xff0c;只是内置好运行环境 随便找个目录下载paddleocr的代码 git…

死磕P7: JVM垃圾回收那点事,轻松拿捏不是事儿(二)

这是「死磕P7」系列第 004 篇文章&#xff0c;欢迎大家来跟我一起 死磕 100 天&#xff0c;争取在 2025 年来临之际&#xff0c;给自己一个交代。&#xff08;公&号&#xff1a;新质程序猿&#xff0c;更新会更及时&#xff0c;内容也会更全面丰富&#xff0c;欢迎大家关注…

神仙级AI产品经理入门手册,从入门到入魂非常详细,收藏这一篇,少走三年弯路!!!

作为一个产品经理&#xff0c;你可能已经熟悉了一些常见的AI技术和应用&#xff0c;比如机器学习、深度学习、自然语言处理、计算机视觉等。 但是&#xff0c;你是否了解什么是大模型&#xff1f;大模型又有什么特点和优势&#xff1f;为什么大模型会成为AI领域的一个重要趋势…

Llama系列迈向多模态新时代:3.2版本开源超越闭源,并携手Arm推出手机优化版

在多模态领域&#xff0c;开源模型也超闭源了&#xff01; 就在刚刚结束的 Meta 开发者大会上&#xff0c;Llama 3.2 闪亮登场&#xff1a; 这回不仅具备了多模态能力&#xff0c;还和 Arm 等联手&#xff0c;推出了专门为高通和联发科硬件优化的 “移动” 版本。 具体来说&a…

尾矿库安全监测系统:守护矿山安全的关键技术

尾矿库是矿山企业用于存放尾矿的重要设施&#xff0c;其安全状况直接关系到周边环境和人民生命财产安全。近年来&#xff0c;随着技术的不断进步&#xff0c;尾矿库安全监测系统应运而生&#xff0c;为尾矿库的安全管理提供了强有力的技术支持。本文将详细介绍尾矿库安全监测系…

en造数据结构与算法C# 之 二叉排序树的删除

en造数据结构与算法C# 之 二叉排序树的增/查-CSDN博客 删除方法比起添加和查找就稍显复杂了 &#xff0c;所以单独拿出来写一篇 分析 输入 1.根节点&#xff0c;用于从根上查找你要删除的节点 2.需要删除的值 public Node<T> Delete(Node<T> root, T data) {if (…

设计模式、系统设计 record part02

软件设计模式&#xff1a; 1.应对重复发生的问题 2.解决方案 3.可以反复使用 1.本质是面向对象 2.优点很多 1.创建型-创建和使用分离 2.结构型-组合 3.行为型-协作 571123种模式 UML-统一建模语言-Unified Modeling Language 1.可视化&#xff0c;图形化 2.各种图&#xff08;9…

SSH连接提示秘钥无效

说明&#xff1a;本文记录一次使用SSH连接服务器失效的问题。 使用SSH命令连接服务器&#xff0c; ssh -i ssh秘钥路径 user192.xx.xx.xx提示下面的错误&#xff1b; Load key "shuhe.bin": invalid format aochuang192.xx.xx.xx: Permission denied (publickey,g…

Python新手学习过程记录之基础环境:环境变量、版本区分、虚拟环境

https://img-blog.csdnimg.cn/img_convert/0604267530a515112e51dfc80d0b0ee7.png 刚开始接触Python并学习一门开发语言,可能就会遇到一些棘手的问题,比如电脑上不知不觉已经安装了多个python版本,python3.8/3.10/3.11,甚至一些软件中也集成有python解释器&#xff1b;那么我编…

每日一题|2516. 每种字符至少取 K 个|双指针、最长子串、字典

本题需要转化求解目标。 对于一个序列&#xff0c;两头收集的最少数量的时候&#xff0c;剩下的部分&#xff08;我们称之为子串&#xff09;就会对应的越长。也就是说&#xff0c;我们只要求解一个满足要求的最长子串&#xff0c;使得两边剩余的字符数量刚好满足要求。 由于…