用Python在Linux下調用新中新DKQ-A16D讀卡器,讀二代證數據


1.背景

最近在研究二代證讀卡器,手頭上的設備是新中新DKQ-A16D,在官網(https://www.onecardok.com.cn/download)逛了一圈,發現Win下的示例,瀏覽器插件很多,Linux下的就少的可憐了,只有“新中新身份證讀卡器開發包Linux版V1.2.1”,“新中新讀卡器麒麟ArmV8火狐擴展程序安裝及使用說明V1.1”,意味着瀏覽器插件還只能在ARM的平台下才能使用。Linux的也只有C++和Java版本。

2.開搞C++

大概看了下C++的Demo,這個Demo主要就是調用CppDemo目錄下的那些libx86,libx64等目錄下的libSynReader.so文件,具體調用的函數如下:

//打開USB通信
int OpenUsbComm();

//讀身份證文字和照片信息
int getIDcard(St_IDCardDataUTF8 *pIDCardDataUTF8);

//解碼照片函數,wltBuffer原始照片1024字節wlt數據,bmpPath 保存照片位置
int saveWlt2Bmp( char* wltBuffer,const char* bmpPath);
int saveWlt2BmpUseFork( char* wltBuffer,const char* bmpPath);

//關閉USB通信
int CloseComm();

流程:先打開USB通信(OpenUsbComm) ---> 讀取身份證文字和照片信息(getIDcard) ---> 解碼照片(saveWlt2Bmp或者saveWlt2BmpUseFork) ---> 關閉USB通信(CloseComm)

至於saveWlt2Bmp和saveWlt2BmpUseFork這兩個函數到底什么區別,不懂。兩個函數調用結果好像都是一樣。

這里需要注意的是getIDcard這個函數,它的參數是一個結構體指針 ,根據CppDemo中的頭文件定義,這個結構體是這樣的:

typedef struct IDCardDataUTF8 {
    char CardType[10];         //I為外國人居住證,J 為港澳台居住證,空格(0x20)為普通身份證
    char Name[40];             //姓名 
    char EngName[130];       //英文名(外國人居住證)
    char Sex[10];           //性別
    char Nation[100];          //民族或國籍(外國人居住證)     
    char Birthday[18];         //出生日期
    char Address[80];       //住址
    char IDCardNo[40];      //身份證號或外國人居住證號(外國人居住證)
    char GrantDept[40];     //發證機關
    char UserLifeBegin[30]; //有效開始日期
    char UserLifeEnd[30];   //有效截止日期
    char PassID[30];        //通行證號碼(港澳台)
    char IssuesTimes[10];    //簽發次數(港澳台)
    char CertVol[10];         //證件版本號(外國人居住證)
    char wlt[1024];           //照片數據
    int isSavePhotoOK;        //照片是否解碼保存  0=no  1=yes
    char fp[1024];            //指紋數據
    int isFpRead;            //是否讀取了證內指紋     0=no 1=yes
} St_IDCardDataUTF8, *PSt_IDCardDataUTF8;

 

3.開搞Python

知道了調用哪些函數,知道了流程,接下來就是Python的事了。

在Python中,要調用.so文件,主要是依靠ctypes這個庫。

 具體加載so庫的代碼也簡單,

import ctypes
from ctypes import *

synR = ctypes.cdll.LoadLibrary("/usr/lib/libSynReader64.so")

加載完庫,調用庫中的函數也簡單,

nRet = synR.OpenUsbComm()

nRet是代表打開USB通信時是否成功,等於0代表開啟成功,還有其他的值,具體參見官網下載的那個Linux包里有個word文檔。

接下來就是本文的難點了,在Python中是沒有結構體這個概念的,那getIDcard又要傳一個結構體指針,該怎么辦?

好在ctypes已經幫我們想好了,ctype內置了一個Structure這個類,只要我們創建一個類,繼承自這個類,在類中定義一個_fields_的list,C++那邊就會當作結構體了。具體實現如下:

class IDCardDataUTF8(Structure):
    _fields_ = [
        ("CardType", c_char * 10),  # I為外國人居住證,J 為港澳台居住證,空格(0x20)為普通身份證
        ("Name", c_char * 40),  # 姓名
        ("EngName", c_char * 130),  # 英文名(外國人居住證)
        ("Sex", c_char * 10),  # 性別
        ("Nation", c_char*100),  # 民族或國籍(外國人居住證)
        ("Birthday", c_char*18),  # 出生日期
        ("Address", c_char*80),  # 住址
        ("IDCardNo", c_char*40),  # 身份證號或外國人居住證號(外國人居住證)
        ("GrantDept", c_char*40),  # 發證機關
        ("UserLifeBegin", c_char*30),  # 有效開始日期
        ("UserLifeEnd", c_char*30),  # 有效截止日期
        ("PassID", c_char*30),  # 通行證號碼(港澳台)
        ("IssuesTimes", c_char*10),  # 簽發次數(港澳台)
        ("CertVol", c_char * 10),  # 證件版本號(外國人居住證)
        ("wlt", c_byte*1024),  # 照片數據
        ("isSavePhotoOK", c_int),  # 照片是否解碼保存  0=no  1=yes
        ("fp", c_char*1024),  # 指紋數據
        ("isFpRead", c_int)  # 是否讀取了指紋
    ]

對比下這個結構體和上面C++的結構體,是不是很像?這里有個坑,在下不才,在坑了蹲了2天才跳出來。注意看wlt這項,wlt是存儲照片數據的,C++是定義成char,剛開始我也是跟着用c_char,結果死活解碼不了照片,后面經過2天的各種搜索,各種嘗試,發現這個wlt是一個字節數組,所以需要定義成c_byte,一下子照片就解碼出來了。

至於指紋數據,沒去研究。

OK,結構體准備好了,實例化一個結構體對象,接着就可以調用getIDcard了。具體代碼如下:

data = IDCardDataUTF8()
readRet = synR.getIDcard(byref(data))

這個有個byref代表的就是把data參數變成一個指針,也就是上面C++說的結構體指針。

執行完這句,如果readRet等於0,代表讀取成功,接着就可以從data中拿到身份證上的基本信息了。

print(data.Name.decode('utf-8'))  #身份證上的姓名

接着就是要解碼身份證上的照片信息了。

synR.saveWlt2BmpUseFork(data.wlt, b'photo.bmp')

這行代碼執行后,會在.py同級目錄下生成一個名為photo.bmp的照片文件,照片解碼成功。

最后,就是把USB通信關閉就可以了。

synR.CloseComm()

 

4.結束

有一點要注意的是,需要把CppDemo目錄下對應你系統的libx86或者libx64目錄下的所有so文件拷貝到/usr/lib和/lib目錄下

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM