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

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

作者: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,'',50);

   //memset(inBuffer,'',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,'',512);

  abcv_strUnicode2GB(MSG->name,TMP,30);  

  sprintf( szName,"%s",TMP);       //       姓名:  

  return (0);

}

intabcv_getSex(char * szSex)

{

  memset(TMP,'',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,'',512);   

          memset(outbuf,'',BUFLEN);       

          abcv_getName(TMP);         

          if ((i=g2u(TMP,strlen(TMP),outbuf,BUFLEN))==0 )

          {                

                 gtk_entry_set_text(GTK_ENTRY(entrName),outbuf); 

          }                                 

         

          //显示性别

          memset(TMP,'',512);                    

          abcv_getSex(TMP);

                

          if ((i=g2u(TMP,strlen(TMP),outbuf,BUFLEN))==0 )    

          {                             

              gtk_entry_set_text(GTK_ENTRY(entrSex), outbuf);

          }

          //显示民族

          memset(TMP,'',512);          

          abcv_getchNation(TMP);     

          if ((i=g2u(TMP,strlen(TMP),outbuf,BUFLEN))==0 )    

          {                             

              gtk_entry_set_text(GTK_ENTRY(entrNation), outbuf);

          }

         

          //显示出生日期      

          memset(TMP,'',512);                     

          abcv_getBirth(TMP);        

          if ((i=g2u(TMP,strlen(TMP),outbuf,BUFLEN))==0 )    

          {                             

              gtk_entry_set_text(GTK_ENTRY(entrBirthday), outbuf);

          }

         

          //显示户籍地址

          memset(TMP,'',512);             

          abcv_getAddr(TMP);             

          if ((i=g2u(TMP,strlen(TMP),outbuf,BUFLEN))==0 )    

          {                             

              gtk_entry_set_text(GTK_ENTRY(entrAddr), outbuf);

          }

         //显示身份证号码

          memset(TMP,'',512);             

          abcv_getIdCode(TMP);    

          if ((i=g2u(TMP,strlen(TMP),outbuf,BUFLEN))==0 )    

          {                             

              gtk_entry_set_text(GTK_ENTRY(entrID), outbuf);

          }

          //显示签发机关

          memset(TMP,'',512);                 

          abcv_getIssue(TMP);            

          if ((i=g2u(TMP,strlen(TMP),outbuf,BUFLEN))==0 )    

          {                             

              gtk_entry_set_text(GTK_ENTRY(entrDep), outbuf);

          }

          //显示证件有效期

          memset(TMP,'',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("345247223  345220215");

  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("345217221350257201346234272345205263");

  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("346234211346225210346234237351231220");

  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("346200247  345210253");

  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("351200200345207272");

  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("350257273345215241");

  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("346260221  346227217");

  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("350272253344273275350257201345217267");

  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("345234260  345235200");

  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("347224237  346227245");

  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…

五、市场前景

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

适用范围:

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

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

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

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

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

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

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

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

原文地址:https://www.cnblogs.com/james1207/p/3366067.html