树莓派在身份证件核验领域应用

 

树莓派结合身份证阅读器的应用

作者:Mr.Kim.Wu 

邮箱:mrkimwu@gmail.com

发布:2013-10-08

关键字:RaspberryPi,Raspi,RPI,树莓派,身份证阅读器,二代证,身份证,居民身份证,RFID,NFC,Debian,linux,创客

 

一、简介

1.1 第二代居民身份证

第二代居民身份证是一种既具有视读,又具有机读两种功能的法定有效证件。证件内记录了公民的身份信息,是不可以替代而且不能非法复制、仿制的证件,具有唯一性。自2004年换发第二代居民身份证工作正式开展以来,全国二代证的换发量已接近12亿张,基本上人手一张。

第二代居民身份证是由多层聚酯材料复合而成的单页卡式证件,采用非接触式IC卡技术制作,具备视读和机读两种功能。证件尺寸设计长85.6毫米,宽54毫米,厚1.0毫米。证件正面有姓名、性别、民族、出生日期、常住户口所在地住址、公民身份号码和本人相片7个登记项目,印有彩色花纹。证件背面有签发机关和有效期限2个登记项目,印有国徽图案、证件名称、写意长城图案和彩色花纹。

第二代居民身份证有六大变化:融入RFID技术、防伪性能提高、办证时间缩短、存储信息增多、有效期重新确定、发放范围扩大等。

 

1.2 身份证阅读器

居民身份证阅读器接口技术规范符合GA 467-2004国家标准,新制定的标准里增加了指纹内容。

二代身份证读卡器是一种能判断身份证是否伪造的设备,像验钞机一样,能对身份证真伪进行有效识别,二代证内含有RFID芯片,通过二代身份证读卡器,身份证芯片内所存储信息,包括姓名,地址,照片等信息将一一显示,二代证芯片采用智能卡技术,其芯片无法复制,高度防伪,配合二代身份证读卡器,假身份证将无处藏身。可读取、查询第二代居民身份证全部信息,可验证第二代居民身份证真伪。

具有以下特点:

● 通用性强:支持WIN98/2000/XP/NT/WINCE/LINUX等多种操作系统。

● 开放性好:提供SDK供系统集成商进行二次开发。

● 功能强大:可外接标准键盘、鼠标、显示器,提供RS-232C、USB计算机接口。

● 扩展灵活:可加装指纹采集器,现场比对持证人的指纹,进行“人证同一性”认定。也可以外接数码采集设备,采集个人相片、文字等信息,作信息采集设备使用。

● 操作简便:开机即进入阅读界面,阅读软件自动找卡和阅读。

 

1.3 树莓派 Raspberry Pi

树莓派(英语:RaspberryPi),是一款基于Linux系统的只有一张信用卡大小的单板机计算机。它由英国的树莓派基金会所开发,目的是以低价硬件及自由软件刺激在学校的基本的电脑科学教育。

相关介绍请参考维基:

http://zh.wikipedia.org/wiki/%E6%A0%91%E8%8E%93%E6%B4%BE


树莓派板载2个USB接口,以及丰富的外设端口,方便与各类外设通讯。

本文实现了树莓派与身份证阅读器的连接,阅读显示身份证芯片内容。

二、准备工作

2.1设备清单:

l       树莓派+ SD卡Class 4/ Class 10 8G

l       USB转RS232串口线:ProlificUSB-to-Serial Bridg Y-105 (PL2303HX)

l       RS232接口身份证阅读器

l       TP-Link无线网络路由器

 

 

2.2软件

l       字符终端:SecureCRT软件

l       文件传输: FileZilla软件 SFTP(SSH2)传输协议

l       远程桌面:

u     Windows:VNC Viewer或UltraVNC-Viewer

u     Android:AndroidVNC

三、实现步骤

3.1连接方式

本文使用树莓派板载USB口,通过USB转换线转成UART RS232串口与身份证9针RS232串口相连: USB<->RS232

USB 驱动:免驱动安装

在树莓派USB口插上阅读器之后查看USB<-> RS232设备:

ls -l /dev/ttyUSB0

如果直接使用树莓派板载GPIOTTL串口ttyAMA0可参考下面2个网址:

http://www.savagehomeautomation.com/projects/raspberry-pi-rs232-serial-interface-options-revisit.html

http://www.irrational.net/2012/04/19/using-the-raspberry-pis-serial-port/

注意:树莓派板载TTL串口不可直接与身份证阅读器串口相连,电平不匹配容易损坏树莓派板载TTL串口。

 

3.2开发工具链

开发语言:

G++开发底层通讯库。

界面开发语言:本文使用GTK+(GIMP Toolkit)作开发界面

界面设计工具:Glade

其他可选语言:Python、Java、QT、LazarusPascal

 

3.3软件开发

本文采用调用串口设备/dev/ttyUSB0的方法。

另外一种是直接调用身份证阅读器的USB IO管道 Pipe驱动设备,

这种方法需要开发专用USB驱动,需熟悉USB协议,比较麻烦。

 

首先保证串口转换线能用。

短接RS232串口的2,3脚。

编写串口测试程序一:

参考:https://sites.google.com/site/semilleroadt/raspberry-pi-tutorials/gpio

去这个网站下载并安装最新的Pyserial库 

http://sourceforge.net/projects/pyserial/files/pyserial/

//Python测试程序 testserial.py 

import serial
ser =serial.Serial("/dev/ttyUSB0",115200,timeout=1)
ser.write("UARTthe Font")
read =ser.read(13)
print read
ser.close()

运行Python testserial.py 

可以在终端看到输出一串字符UARTthe Font,如果不短接2,3脚将会在超时1秒后程序自动退出,直接换行输出空白。

串口测试方法二:

http://raspberrypi.stackexchange.com/questions/4801/usart-resending-problem-via-console
    在SSH字符终端输入

sudo stty 115200-F /dev/ttyUSB0 -echo -onlcr
cat /dev/ttyUSB0

在VNC远程桌面终端输入

echo hello>> /dev/ttyUSB0

 

授权许可:

身份证阅读器通讯库代码ABCVUtility.cpp、ABCVlib.cpp采用开源GPL授权许可协议,照片图像解码需采用公安专用授权许可协议。详请联系作者。

 

阅读器串口通讯协议(具体请参考标准GA 467-2004):

树莓派与身份阅读器采用命令/应答方式进行数据交换。

数据通讯帧格式:

命令数据输入帧格式

帧头

长度H

长度L

命令码

命令参数

数据内容

校验和

应答数据输出帧格式

帧头

长度H

长度L

SW1

状态

SW2

状态SW3

数据内容

校验和

 

身份证芯片存储编码格式:

文字:256字节Unicode 编码,可转换成GBK码。

照片:1024字节图像压缩编码。

 

开始敲代码:


///

//ABCVlib.cpp代码

#include<stdio.h>
#include<fcntl.h>
#include<time.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h> 
#include"ABCVlib.h"
#include"ABCVUtility.h"
 
 
/*帧头*/
#define Preamble00xDD
#define Preamble10xDD
#define Preamble20xDD
#define Preamble30xDD
#define Preamble40xDD
 
 
 
/*返回错误代码*/
#define         RD_OK             0     //操作成功
#define   OPENPORT_ERR      -1    //打开端口失败
#define   TIMEOUT_ERR       -2    //超时
#define         RD_CARD_ERR      -3    //无卡或读卡失败
 
#define   CHECKSUM_ERR      -4    //校验和错
#define   FILE_ERR          -5    //读卡结果文件打开出错
 
/*机器命令码*/
const unsignedchar CMD_SAM_READALLMSG[2]={0x00, 0x00};
 
/*机器响应命令*/
#define SW1      inBuffer[7]
#define SW2      inBuffer[8]
#define SW3      inBuffer[9]
#define SAMSTATE     inBuffer[9]
#defineRD_SAM_OK    0x90          //操作成功
 
struct defMsg{
  unsigned char name[30];
  unsigned char sex[2];
  unsigned char nation[4];
  unsigned char bY[8],bM[4],bD[4];
  unsigned char address[70];
  unsigned char id[36];
  unsigned char depart[30];
  unsigned char tsY[8],tsM[4],tsD[4];
  unsigned char tpY[8],tpM[4],tpD[4];
};
 
#define MSG((struct defMsg *)&inBufferTMP[0])
 
 
unsigned charinBuffer[2500],inBufferTMP[2500], outBuffer[50];
unsigned longnBytesWrite=0;
int CheckSum=0;
char TMP[512];
charchNation[100];
 
/*******************************************************************************
函数名:     *  abcv_SetPreamble      添加数据帧头
输入参数:   *   无
输出参数:   *   无
*******************************************************************************/
voidabcv_SetPreamble()
{
    outBuffer[0]=Preamble0; 
    outBuffer[1]=Preamble1;  outBuffer[2]=Preamble2;
    outBuffer[3]=Preamble3;  outBuffer[4]=Preamble4;  CheckSum=0;
    nBytesWrite=0x05;   
}
 
/*******************************************************************************
函数名:     *  abcv_CheckControlCode           加入待发数据
输入参数:   *  unsigned char value        加入的数据
输出参数:   *   无
*******************************************************************************/
voidabcv_CheckControlCode(unsigned char value)
{
    CheckSum ^= value;
    outBuffer[nBytesWrite]=value;   
    nBytesWrite++; 
}
 
 
int abcv_ReadMsg(intterm, int port, int timeout, unsigned char *pucCHMsg, int *piCHMsgLen, unsignedchar *pucPHMsg, int *piPHMsgLen)
{
   int Rtn=0;   int i=0;   int nBytes=0;
   FILE *f;
   //unsigned char TMP[512];
   //unsigned char chNation[100];
  
       if(abcv_openPort(term,port)== -1) return (OPENPORT_ERR);
      
   memset(outBuffer,'\0',50);
   //memset(inBuffer,'\0',2500);  
   abcv_SetPreamble();
   abcv_CheckControlCode(0x00); 
   abcv_CheckControlCode(0x03); 
   abcv_CheckControlCode(CMD_SAM_READALLMSG[0]); 
   abcv_CheckControlCode(CMD_SAM_READALLMSG[1]); 
   abcv_CheckControlCode(CheckSum);
  
   abcv_write_n(term, outBuffer, nBytesWrite);
   //接收帧头  
       Rtn= abcv_read_n(term, inBuffer, 7, timeout);        
       if(Rtn<7)
       {
          abcv_closePort(term);
           return(TIMEOUT_ERR);      //接收超时  
   }         
   if(inBuffer[0]!=Preamble0 ||inBuffer[1]!=Preamble1 ||
          inBuffer[2]!=Preamble2|| inBuffer[3]!=Preamble3 ||
          inBuffer[4]!=Preamble4)
        {
          abcv_closePort(term);
          return(TIMEOUT_ERR);      //接收超时  
   } 
       nBytes=inBuffer[5]*256+inBuffer[6];//计算数据长度
         
   //接收指定长度的数据
   Rtn = abcv_read_n(term, &inBuffer[7],nBytes, timeout);           
       abcv_closePort(term);   
      
       if(Rtn<nBytes)
       {
          abcv_closePort(term);
          return(TIMEOUT_ERR);      //接收超时  
   } 
   CheckSum=0;
   for (i=5;i<nBytes+6;i++)
        CheckSum^=inBuffer[i];
       if(CheckSum!=inBuffer[nBytes+6])
       {
          abcv_closePort(term);
          return(CHECKSUM_ERR);      //校验和错  
   } 
   //返回状态码 
      if(SW1==0x00 && SW2==0x00 && SW3==RD_SAM_OK)
      {         
          *piCHMsgLen=256;    
          *piPHMsgLen=1024;          
          memcpy(pucCHMsg,&inBuffer[14],256);
          memcpy(pucPHMsg,&inBuffer[270],1024);
          memcpy(inBufferTMP,&inBuffer[14],256);
          return (RD_OK);            
      }
      else 
   {         
          return(RD_CARD_ERR);
       }
        return (RD_CARD_ERR);     
        
}
 
 
intabcv_ReadIDCard(int term, int port, int timeout,
          unsigned char *pucCHMsg, int*piCHMsgLen, unsigned char *pucPHMsg, int *piPHMsgLen)
         
{
   int RTN;
   FILE *f;
   char *wzfile="./wz.txt";
   char *wltfile="./xp.wlt";
  char*bmpfile="./xp.bmp";     
 
       unsignedchar CHMsg[512],PHMsg[1024];
       unsignedint CHMsgLen,PHMsgLen;
 
       RTN=abcv_ReadMsg(term,port, timeout, CHMsg,&CHMsgLen,PHMsg,&PHMsgLen);   
       if(RTN!=RD_OK) return(RTN);
     
      *piCHMsgLen=256;    
      *piPHMsgLen=1024;
      memcpy(pucCHMsg,CHMsg,256);
      memcpy(pucPHMsg,PHMsg,1024);      
   
      
       f=fopen(wzfile,"wb");
       if(f==NULL) return(FILE_ERR);           
   if (fwrite(CHMsg,CHMsgLen,1,f)!=1){
       fclose(f);
       return(FILE_ERR);
       }           
       fclose(f);
      
           
       f=fopen(wltfile,"wb");
   if (f==NULL) return(FILE_ERR); 
   if (fwrite(PHMsg,PHMsgLen,1,f)!=1){   
       fclose(f);
       return(FILE_ERR);
   }
   fclose(f);         
  
   //
 
    return(RD_OK);   
}
 
 
 
intabcv_getName(char * szName)
{
  memset(TMP,'\0',512);
  abcv_strUnicode2GB(MSG->name,TMP,30);  
  sprintf( szName,"%s",TMP);       //       姓名:  
  return (0);
}
 
intabcv_getSex(char * szSex)
{
  memset(TMP,'\0',512);       
  abcv_strUnicode2GB(MSG->sex,TMP,2);
                              
  if ( memcmp(TMP,"1",1)==0 )
   sprintf( szSex,"男");     //       性别:
  else
   sprintf( szSex,"女");
      
  return (0);
}
//… … 

/

以上cpp 的Makefile:

#
# libABCVLib.soMakefile
#
 
ARM_PREFIX=arm-linux-gnueabihf-
CC   = $(ARM_PREFIX)g++
LD      := ld
CFLAGS  := -fpermissive
LDFLAGS := -shared-fpic
SOURCE  := $(wildcard *.cpp)
OBJS    := $(patsubst %.cpp,%.o,$(SOURCE))
TARGET_LIB := libABCVLib.so
 
all:$(OBJS)
       echo $(OBJS)
       $(LD) $(LDFLAGS) -o $(TARGET_LIB) $(OBJS)
 
%.o:%.cpp
       @echo Compiling $< ...
       $(CC) -c $(CFLAGS)  $< -o $*.o
        
.PHONY: clean
 
clean:
       rm *.so *.o –rf

 

 

so编译环境设置:

生成的共享库libABCVLib.so在非标准路经,ld.so 怎么找到它呢?

目前,Linux 通用的做法是将非标准路经加入 /etc/ld.so.conf,然后运行 ldconfig 生成 /etc/ld.so.cache。ld.so加载共享库的时候,会从ld.so.cache 查找。

或者在/etc/ld.so.conf.d/目录下新建一个共享库名字对应的conf文件:libABCVLib.conf,文件内容为你的工作目录,本文为/home/pi/kim/gtk30

 

图形界面: 采用GTK+图形工具包调用libABCVLib.so 动态库显示身份证文字和照片。

图形界面开发参考网址:http://hertaville.com/2012/09/28/development-environment-raspberry-pi-cross-compiler/http://hertaville.com/2013/07/19/cross-compiling-gtk-applications-for-the-raspberry-pi/

//gtktest.c
#include<gtk/gtk.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#include<termio.h>
#include<unistd.h>
#include<errno.h>
#include<iconv.h>
#include<locale.h>
#include<ABCVlib.h> 
 
#defineTERM_TYPE       1                //终端类型 默认1
#defineTERM_PORT       1               //阅读机具所接的串口号
                                        //1:主机串口一
#defineTIMEOUT         4               //读卡超时4秒返回
#define BUFLEN 255 
 
  GtkWidget *window;
  GtkWidget *frame; 
  GtkWidget *label;
  GtkWidget *plus;
  GtkWidget *minus;
 
  GtkWidget *fixed1;
  GtkWidget *entrName;
  GtkWidget *entrSex;
  GtkWidget *label1;
  GtkWidget *entrNation;
  GtkWidget *entrBirthday;
  GtkWidget *entrAddr;
  GtkWidget *entrID;
  GtkWidget *entrDep;
  GtkWidget *entrValid;
  GtkWidget *label7;
  GtkWidget *label9;
  GtkWidget *hseparator1;
  GtkWidget *label2;
  GtkWidget *bt_close;
  GtkWidget *button1;
  GtkWidget *label3;
  GtkWidget *label6;
  GtkWidget *label5;
  GtkWidget *label4;
  GtkWidget *image;
 
//代码转换:从一种编码转为另一种编码
int code_convert(char*from_charset,char *to_charset,char *inbuf,int inlen,char *outbuf,int outlen)
{
   iconv_t cd;
   int rc;
   char **pin = &inbuf;
   char **pout = &outbuf;
 
   cd = iconv_open(to_charset,from_charset);
   if (cd==0) return -1;
   memset(outbuf,0,outlen);
   if (iconv(cd,pin,&inlen,pout,&outlen)==-1)return -1;
   iconv_close(cd);
   return 0;
}
//UNICODE码utf-8转为GB码
int u2g(char *inbuf,int inlen,char *outbuf,intoutlen)
{
   returncode_convert("utf-8","gb2312",inbuf,inlen,outbuf,outlen);
}
//GB码转为UNICODE码utf-8
int g2u(char*inbuf,size_t inlen,char *outbuf,size_t outlen)
{
   returncode_convert("gb2312","utf-8",inbuf,inlen,outbuf,outlen);
}
 
voidon_bt_close_clicked(GtkButton *button,gpointer user_data)
{
   gtk_main_quit();
}
 
voidon_bt_ok_clicked (GtkButton *button,gpointer user_data)
{
 
  inti,Len,nRet,zpLen;   
   unsigned char Buff[500];
   char outbuf[BUFLEN];
   unsigned char zpBuff[1024];
   char TMP[512];
   char *wltfile="./xp.wlt";
  char*bmpfile="./xp.bmp";     
  FILE*f;                           
                                   
 //调用libABCVLib.so 动态库阅读身份证,自动生成文字和照片文件                                 
  nRet =abcv_ReadIDCard (TERM_TYPE, TERM_PORT,TIMEOUT, Buff, &Len, zpBuff, &zpLen); //libABCVLib.so 
  if (nRet==0)
   {
         //显示姓名
           memset(TMP,'\0',512);   
          memset(outbuf,'\0',BUFLEN);       
          abcv_getName(TMP);         
          if ((i=g2u(TMP,strlen(TMP),outbuf,BUFLEN))==0 )
          {                
                 gtk_entry_set_text(GTK_ENTRY(entrName),outbuf); 
          }                                 
         
          //显示性别
          memset(TMP,'\0',512);                    
          abcv_getSex(TMP);
                
          if ((i=g2u(TMP,strlen(TMP),outbuf,BUFLEN))==0 )    
          {                             
              gtk_entry_set_text(GTK_ENTRY(entrSex), outbuf);
          }
          //显示民族
          memset(TMP,'\0',512);          
          abcv_getchNation(TMP);     
          if ((i=g2u(TMP,strlen(TMP),outbuf,BUFLEN))==0 )    
          {                             
              gtk_entry_set_text(GTK_ENTRY(entrNation), outbuf);
          }
         
          //显示出生日期      
          memset(TMP,'\0',512);                     
          abcv_getBirth(TMP);        
          if ((i=g2u(TMP,strlen(TMP),outbuf,BUFLEN))==0 )    
          {                             
              gtk_entry_set_text(GTK_ENTRY(entrBirthday), outbuf);
          }
         
          //显示户籍地址
          memset(TMP,'\0',512);             
          abcv_getAddr(TMP);             
          if ((i=g2u(TMP,strlen(TMP),outbuf,BUFLEN))==0 )    
          {                             
              gtk_entry_set_text(GTK_ENTRY(entrAddr), outbuf);
          }
         //显示身份证号码
          memset(TMP,'\0',512);             
          abcv_getIdCode(TMP);    
          if ((i=g2u(TMP,strlen(TMP),outbuf,BUFLEN))==0 )    
          {                             
              gtk_entry_set_text(GTK_ENTRY(entrID), outbuf);
          }
          //显示签发机关
          memset(TMP,'\0',512);                 
          abcv_getIssue(TMP);            
          if ((i=g2u(TMP,strlen(TMP),outbuf,BUFLEN))==0 )    
          {                             
              gtk_entry_set_text(GTK_ENTRY(entrDep), outbuf);
          }
          //显示证件有效期
          memset(TMP,'\0',512);             
          abcv_getValidity(TMP);                   
          if ((i=g2u(TMP,strlen(TMP),outbuf,BUFLEN))==0 )    
          {                             
              gtk_entry_set_text(GTK_ENTRY(entrValid), outbuf);
          }
             
          //显示身份证照片
          image =gtk_image_new_from_file(bmpfile);
          gtk_widget_set_size_request(image,102, 126);
          gtk_widget_show (image);     
          gtk_fixed_put (GTK_FIXED (fixed1),image, 438, 160);
                           
   }
   else {
       g_warning ("Error Code: %d", nRet);   
   }
}
 
  
 
int main(int argc,char** argv) {  
 
  gtk_init(&argc, &argv);
 
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);
  gtk_window_set_default_size (GTK_WINDOW(window), 580, 400);
  gtk_window_set_title(GTK_WINDOW(window),"Raspi IDCard2 Reader"); 
 
  fixed1 = gtk_fixed_new ();
  gtk_widget_show (fixed1);
  gtk_container_add (GTK_CONTAINER (window),fixed1);
  gtk_widget_set_size_request (fixed1, 286,123);
 
  entrName = gtk_entry_new ();
  gtk_widget_show (entrName);
  gtk_fixed_put (GTK_FIXED (fixed1), entrName,96, 16);
  gtk_widget_set_size_request (entrName, 158,25);
 
  entrSex = gtk_entry_new ();
  gtk_widget_show (entrSex);
  gtk_fixed_put (GTK_FIXED (fixed1), entrSex,96, 72);
  gtk_widget_set_size_request (entrSex, 84,25);
 
  label1 = gtk_label_new("\345\247\223  \345\220\215");
  gtk_widget_show (label1);
  gtk_fixed_put (GTK_FIXED (fixed1), label1, 8,23);
  gtk_widget_set_size_request (label1, 82, 17);
 
  entrNation = gtk_entry_new ();
  gtk_widget_show (entrNation);
  gtk_fixed_put (GTK_FIXED (fixed1),entrNation, 344, 72);
  gtk_widget_set_size_request (entrNation, 84,25);
 
  entrBirthday = gtk_entry_new ();
  gtk_widget_show (entrBirthday);
  gtk_fixed_put (GTK_FIXED (fixed1),entrBirthday, 96, 112);
  gtk_widget_set_size_request (entrBirthday,160, 25);
 
  entrAddr = gtk_entry_new ();
  gtk_widget_show (entrAddr);
  gtk_fixed_put (GTK_FIXED (fixed1), entrAddr,96, 160);
  gtk_widget_set_size_request (entrAddr, 331,25);
 
  entrID = gtk_entry_new ();
  gtk_widget_show (entrID);
  gtk_fixed_put (GTK_FIXED (fixed1), entrID,96, 200);
  gtk_widget_set_size_request (entrID, 331,25);
 
  entrDep = gtk_entry_new ();
  gtk_widget_show (entrDep);
  gtk_fixed_put (GTK_FIXED (fixed1), entrDep,96, 240);
  gtk_widget_set_size_request (entrDep, 331,25);
 
  entrValid = gtk_entry_new ();
  gtk_widget_show (entrValid);
  gtk_fixed_put (GTK_FIXED (fixed1), entrValid,96, 280);
  gtk_widget_set_size_request (entrValid, 331,25);
 
  label7 = gtk_label_new("\345\217\221\350\257\201\346\234\272\345\205\263");
  gtk_widget_show (label7);
  gtk_fixed_put (GTK_FIXED (fixed1), label7,16, 240);
  gtk_widget_set_size_request (label7, 68, 25);
 
  label9 = gtk_label_new("\346\234\211\346\225\210\346\234\237\351\231\220");
  gtk_widget_show (label9);
  gtk_fixed_put (GTK_FIXED (fixed1), label9,16, 280);
  gtk_widget_set_size_request (label9, 68, 17);
 
  hseparator1 = gtk_hseparator_new ();
  gtk_widget_show (hseparator1);
  gtk_fixed_put (GTK_FIXED (fixed1),hseparator1, 24, 312);
  gtk_widget_set_size_request (hseparator1,426, 16);
 
  label2 = gtk_label_new("\346\200\247  \345\210\253");
  gtk_widget_show (label2);
  gtk_fixed_put (GTK_FIXED (fixed1), label2,16, 80);
  gtk_widget_set_size_request (label2, 64, 17);
 
  bt_close = gtk_button_new_with_mnemonic("\351\200\200\345\207\272");
  gtk_widget_show (bt_close);
  gtk_fixed_put (GTK_FIXED (fixed1), bt_close,296, 336);
  gtk_widget_set_size_request (bt_close, 53,27);
 
  button1 = gtk_button_new_with_mnemonic("\350\257\273\345\215\241");
  gtk_widget_show (button1);
  gtk_fixed_put (GTK_FIXED (fixed1), button1,152, 336);
  gtk_widget_set_size_request (button1, 53, 27);
 
  label3 = gtk_label_new("\346\260\221  \346\227\217");
  gtk_widget_show (label3);
  gtk_fixed_put (GTK_FIXED (fixed1), label3,280, 80);
  gtk_widget_set_size_request (label3, 64, 17);
 
  label6 = gtk_label_new("\350\272\253\344\273\275\350\257\201\345\217\267");
  gtk_widget_show (label6);
  gtk_fixed_put (GTK_FIXED (fixed1), label6,16, 208);
  gtk_widget_set_size_request (label6, 69, 17);
 
  label5 = gtk_label_new("\345\234\260  \345\235\200");
  gtk_widget_show (label5);
  gtk_fixed_put (GTK_FIXED (fixed1), label5,16, 168);
  gtk_widget_set_size_request (label5, 64, 17);
 
  label4 = gtk_label_new("\347\224\237  \346\227\245");
  gtk_widget_show (label4);
  gtk_fixed_put (GTK_FIXED (fixed1), label4,16, 120);
  gtk_widget_set_size_request (label4, 64,17); 
  
 
 
  g_signal_connect ((gpointer) bt_close,"clicked",
                    G_CALLBACK(on_bt_close_clicked),
                    NULL);
                   
  g_signal_connect ((gpointer) button1,"clicked",
                    G_CALLBACK(on_bt_ok_clicked),
                    NULL);
 
  gtk_widget_show_all(window);  
  gtk_main();
 
  return 0;
} 

直接在树莓派上编译gtktest.c:

GTK+ Makefile文件:

ARM_PREFIX=arm-linux-gnueabihf-
CC   = $(ARM_PREFIX)gcc
SRC += gtktest.c
TARGET = gtktest
 
LIBRARY += gtk-3
LIBRARY += gdk-3
LIBRARY += atk-1.0
LIBRARY += gio-2.0
LIBRARY +=pangocairo-1.0
LIBRARY +=gdk_pixbuf-2.0
LIBRARY +=cairo-gobject
LIBRARY +=pango-1.0
LIBRARY += cairo
LIBRARY +=gobject-2.0
LIBRARY +=glib-2.0
LIBRARY += stdc++
LIBRARY+= ABCVLib
LIBRARY += dl
 
LIBRARYDIR +=/lib/arm-linux-gnueabihf
LIBRARYDIR +=/usr/lib/arm-linux-gnueabihf
LIBRARYDIR += /lib
LIBRARYDIR +=/usr/lib
 
#请改成你自己的工作目录
LIBRARYDIR+= /home/pi/kim/gtk30
 
XLINK_LIBDIR +=/lib/arm-linux-gnueabihf
XLINK_LIBDIR +=/usr/lib/arm-linux-gnueabihf
 
INCLUDEDIR +=/usr/include/gtk-3.0
INCLUDEDIR +=/usr/include/pango-1.0
INCLUDEDIR +=/usr/include/gio-unix-2.0/
INCLUDEDIR +=/usr/include/atk-1.0
INCLUDEDIR +=/usr/include/cairo
INCLUDEDIR +=/usr/include/gdk-pixbuf-2.0
INCLUDEDIR +=/usr/include/freetype2
INCLUDEDIR +=/usr/include/glib-2.0
INCLUDEDIR +=/usr/lib/arm-linux-gnueabihf/glib-2.0/include
INCLUDEDIR +=/usr/include/pixman-1
INCLUDEDIR +=/usr/include/libpng12
#请改成你自己的工作目录
INCLUDEDIR+= /home/pi/kim/gtk30
 
OPT = -O0
DEBUG = -g
WARN= -Wall  -Wextra -pedantic
PTHREAD= -pthread
 
INCDIR  = $(patsubst %,-I%,$(INCLUDEDIR))
LIBDIR  = $(patsubst %,-L%,$(LIBRARYDIR))
LIB    = $(patsubst %, -l%,$(LIBRARY))
XLINKDIR =$(patsubst %,-Xlinker -rpath-link=%,$(XLINK_LIBDIR))
 
all:
   $(CC) $(OPT) $(DEBUG) $(WARN) $(LIBDIR)$(PTHREAD) $(INCDIR) $(XLINKDIR) $(LIB) $(SRC) -o $(TARGET)
 
clean:
   rm -rf $(TARGET)

3.4 身份证阅读运行效果(在电脑VNC显示读卡界面)

依次输入:

$make
$./gtktest


当然也可直接在安卓手机VNC界面下打开阅读界面并显示读卡结果:

 

 

 

附:用Lazarus Pascal设计树莓派下图形界面:


还可在Windows环境下交叉设计编译,正如其所说的一次编译到处运行:


在Windows下执行Lazarus设计的程序:


四、扩展应用

与手机结合、触摸屏、摄像头、指纹头、打印机、蓝牙、NFC…

 

 

五、市场前景

该设备应用领域:自助设备、手持设备、物联网、安防门禁…

 

适用范围:

●公安:身份证申领、户口登记迁移、人口管理等。 旅馆:住宿登记等。

●民政:求学、就业、参军、婚姻登记等。

●民航:机票购买、登机等。

●银行:开户、信用卡交易、大额取款等。

●邮局:领取邮件汇款等。

●电信:电话手机开户、各种通信业务等。

●证券:股票、期货交易等。

●企事业单位:招工、来访登记

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值