安卓識別身份證,自動提取身份證資訊功能實現(附原始碼)
阿新 • • 發佈:2018-11-21
原始碼下載地址:注:原始碼裡沒有騰訊優圖的賬號需要填寫自己的 下載地址
先講幾下.首先我們需要去騰訊優圖申請一個賬號,因為身份證識別需要用到第三方介面如圖所示
我申請的是掃描身份證,當然還有其他的功能,比如掃描銀行卡,營業執照,車牌等等 ,大家可以去研究一下
1.記得配許可權,需要讀寫SD卡 ,還需要網路的許可權 記得引入第三方庫,本人很懶,反正能少些程式碼的,絕對不手打,能用第三庫解決的,絕不自己動手,哈哈
//網路請求庫 compile 'org.xutils:xutils:3.3.36' //圖片選擇器庫 compile 'com.github.LuckSiege.PictureSelector:picture_library:v2.2.3' //解析庫 compile 'com.google.code.gson:gson:2.7'
還有,記得在allprojects新增下程式碼
allprojects {
repositories {
maven { url 'https://jitpack.io' }
maven { url 'https://maven.google.com' }
//圖片選擇器庫
maven {
url "http://dl.bintray.com/nuptboyzhb/maven"
}
google()
jcenter()
}
}
下面配置好許可權
<!-- 讀寫 --> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> <!-- 用於申請呼叫照相機 --> <uses-permission android:name="android.permission.CAMERA" />
然後新建一個Application配置下網路請求吧
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//網路請求
x.Ext.init(this);
}
}
記得在Manifests中設定一下name=.MyApplication
<application android:name=".MyApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme">
接下來是佈局檔案來,等會上程式碼了
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:scrollbars="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/activity_autonym_certification_iv_positive"
android:layout_width="match_parent"
android:layout_height="180dp"
android:layout_marginRight="30dp"
android:layout_marginLeft="30dp"
android:layout_marginTop="20dp"
android:background="@drawable/autonym_certification_iv_line"
android:padding="20dp"
android:src="@mipmap/idcard_positive" />
<ImageView
android:id="@+id/activity_autonym_certification_iv_reverse"
android:layout_width="match_parent"
android:layout_height="180dp"
android:layout_marginTop="25dp"
android:layout_marginRight="30dp"
android:layout_marginLeft="30dp"
android:background="@drawable/autonym_certification_iv_line"
android:padding="20dp"
android:src="@mipmap/idcard_reverse" />
<LinearLayout
android:layout_marginRight="30dp"
android:layout_marginLeft="30dp"
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="90dp"
android:layout_height="wrap_content"
android:text="姓名:"
android:textColor="@color/black"/>
<EditText
android:enabled="false"
android:id="@+id/activity_autonym_certification_et_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:gravity="center"
android:background="@drawable/autonym_certification_iv_line"
android:text=""/>
</LinearLayout>
<LinearLayout
android:layout_marginTop="10dp"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="90dp"
android:layout_height="wrap_content"
android:text="有效日期:"
android:textColor="@color/black"/>
<EditText
android:enabled="false"
android:id="@+id/activity_autonym_certification_et_effective_date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:gravity="center"
android:background="@drawable/autonym_certification_iv_line"
android:text=""/>
</LinearLayout>
<LinearLayout
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="90dp"
android:layout_height="wrap_content"
android:text="身份證號碼:"
android:textColor="@color/black"/>
<EditText
android:id="@+id/activity_autonym_certification_et_id_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:gravity="center"
android:enabled="false"
android:background="@drawable/autonym_certification_iv_line"
android:text=""/>
</LinearLayout>
</LinearLayout>
</ScrollView>
</LinearLayout>
然後是兩個實體類用來存放身份證 正反兩面的資料,先是正面
package com.example.aa.demo.entity;
import java.io.Serializable;
import java.util.List;
/**
* 識別結果實體
*/
public class IdentifyResult implements Serializable {
/**
* errorcode : 0
* errormsg : OK
* name : xxx
* name_confidence_all : [50,60,53]
* sex : xx
* sex_confidence_all : [41]
* nation : xx
* nation_confidence_all : [38]
* birth : xxxx/xx/xx
* birth_confidence_all : [69,43,46,46,44,53,50]
* address : xxxxxxxxx
* address_confidence_all : [43,36,34,17,25,24,21,31,45,36,23,62,12,30,9,1,39,34,24,19,16,30,30,4]
* id : xxxxxxxxxxxxxxxxxx
* id_confidence_all : [52,58,59,73,54,56,61,63,50,63,60,49,72,50,62,57,63,53]
* frontimage : xxx
* frontimage_confidence_all : []
* watermask_confidence_all : []
* valid_date_confidence_all : []
* authority_confidence_all : []
* backimage_confidence_all : []
* detail_errorcode : []
* detail_errormsg : []
*/
private int errorcode;
private String errormsg;
private String name;
private String sex;
private String nation;
private String birth;
private String address;
private String id;
private String frontimage;
private List<Integer> name_confidence_all;
private List<Integer> sex_confidence_all;
private List<Integer> nation_confidence_all;
private List<Integer> birth_confidence_all;
private List<Integer> address_confidence_all;
private List<Integer> id_confidence_all;
private List<?> frontimage_confidence_all;
private List<?> watermask_confidence_all;
private List<?> valid_date_confidence_all;
private List<?> authority_confidence_all;
private List<?> backimage_confidence_all;
private List<Integer> detail_errorcode;
private List<String> detail_errormsg;
public int getErrorcode() {
return errorcode;
}
public void setErrorcode(int errorcode) {
this.errorcode = errorcode;
}
public String getErrormsg() {
return errormsg;
}
public void setErrormsg(String errormsg) {
this.errormsg = errormsg;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getNation() {
return nation;
}
public void setNation(String nation) {
this.nation = nation;
}
public String getBirth() {
return birth;
}
public void setBirth(String birth) {
this.birth = birth;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getFrontimage() {
return frontimage;
}
public void setFrontimage(String frontimage) {
this.frontimage = frontimage;
}
public List<Integer> getName_confidence_all() {
return name_confidence_all;
}
public void setName_confidence_all(List<Integer> name_confidence_all) {
this.name_confidence_all = name_confidence_all;
}
public List<Integer> getSex_confidence_all() {
return sex_confidence_all;
}
public void setSex_confidence_all(List<Integer> sex_confidence_all) {
this.sex_confidence_all = sex_confidence_all;
}
public List<Integer> getNation_confidence_all() {
return nation_confidence_all;
}
public void setNation_confidence_all(List<Integer> nation_confidence_all) {
this.nation_confidence_all = nation_confidence_all;
}
public List<Integer> getBirth_confidence_all() {
return birth_confidence_all;
}
public void setBirth_confidence_all(List<Integer> birth_confidence_all) {
this.birth_confidence_all = birth_confidence_all;
}
public List<Integer> getAddress_confidence_all() {
return address_confidence_all;
}
public void setAddress_confidence_all(List<Integer> address_confidence_all) {
this.address_confidence_all = address_confidence_all;
}
public List<Integer> getId_confidence_all() {
return id_confidence_all;
}
public void setId_confidence_all(List<Integer> id_confidence_all) {
this.id_confidence_all = id_confidence_all;
}
public List<?> getFrontimage_confidence_all() {
return frontimage_confidence_all;
}
public void setFrontimage_confidence_all(List<?> frontimage_confidence_all) {
this.frontimage_confidence_all = frontimage_confidence_all;
}
public List<?> getWatermask_confidence_all() {
return watermask_confidence_all;
}
public void setWatermask_confidence_all(List<?> watermask_confidence_all) {
this.watermask_confidence_all = watermask_confidence_all;
}
public List<?> getValid_date_confidence_all() {
return valid_date_confidence_all;
}
public void setValid_date_confidence_all(List<?> valid_date_confidence_all) {
this.valid_date_confidence_all = valid_date_confidence_all;
}
public List<?> getAuthority_confidence_all() {
return authority_confidence_all;
}
public void setAuthority_confidence_all(List<?> authority_confidence_all) {
this.authority_confidence_all = authority_confidence_all;
}
public List<?> getBackimage_confidence_all() {
return backimage_confidence_all;
}
public void setBackimage_confidence_all(List<?> backimage_confidence_all) {
this.backimage_confidence_all = backimage_confidence_all;
}
public List<Integer> getDetail_errorcode() {
return detail_errorcode;
}
public void setDetail_errorcode(List<Integer> detail_errorcode) {
this.detail_errorcode = detail_errorcode;
}
public List<String> getDetail_errormsg() {
return detail_errormsg;
}
public void setDetail_errormsg(List<String> detail_errormsg) {
this.detail_errormsg = detail_errormsg;
}
}
再是反面
package com.example.aa.demo.entity;
import java.io.Serializable;
import java.util.List;
/**
* Created by aa on 2018/10/30.
*/
public class cardReverseRusult implements Serializable {
/**
* errorcode : 0
* errormsg : OK
* session_id :
* name_confidence_all : []
* sex_confidence_all : []
* nation_confidence_all : []
* birth_confidence_all : []
* address_confidence_all : []
* id_confidence_all : []
* frontimage_confidence_all : []
* watermask_confidence_all : []
* valid_date : 2010.07.21-2020.07.21
* valid_date_confidence_all : [99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,95,99,99,99,99]
* authority : 趙縣公安局
* authority_confidence_all : [100]
* backimage : .....
* backimage_confidence_all : []
* detail_errorcode : []
* detail_errormsg : []
* card_type : 1
* recognize_warn_code : []
* recognize_warn_msg : []
*/
private int errorcode;
private String errormsg;
private String session_id;
private String valid_date;
private String authority;
private String backimage;
private int card_type;
private List<?> name_confidence_all;
private List<?> sex_confidence_all;
private List<?> nation_confidence_all;
private List<?> birth_confidence_all;
private List<?> address_confidence_all;
private List<?> id_confidence_all;
private List<?> frontimage_confidence_all;
private List<?> watermask_confidence_all;
private List<Integer> valid_date_confidence_all;
private List<Integer> authority_confidence_all;
private List<?> backimage_confidence_all;
private List<?> detail_errorcode;
private List<?> detail_errormsg;
private List<?> recognize_warn_code;
private List<?> recognize_warn_msg;
public int getErrorcode() {
return errorcode;
}
public void setErrorcode(int errorcode) {
this.errorcode = errorcode;
}
public String getErrormsg() {
return errormsg;
}
public void setErrormsg(String errormsg) {
this.errormsg = errormsg;
}
public String getSession_id() {
return session_id;
}
public void setSession_id(String session_id) {
this.session_id = session_id;
}
public String getValid_date() {
return valid_date;
}
public void setValid_date(String valid_date) {
this.valid_date = valid_date;
}
public String getAuthority() {
return authority;
}
public void setAuthority(String authority) {
this.authority = authority;
}
public String getBackimage() {
return backimage;
}
public void setBackimage(String backimage) {
this.backimage = backimage;
}
public int getCard_type() {
return card_type;
}
public void setCard_type(int card_type) {
this.card_type = card_type;
}
public List<?> getName_confidence_all() {
return name_confidence_all;
}
public void setName_confidence_all(List<?> name_confidence_all) {
this.name_confidence_all = name_confidence_all;
}
public List<?> getSex_confidence_all() {
return sex_confidence_all;
}
public void setSex_confidence_all(List<?> sex_confidence_all) {
this.sex_confidence_all = sex_confidence_all;
}
public List<?> getNation_confidence_all() {
return nation_confidence_all;
}
public void setNation_confidence_all(List<?> nation_confidence_all) {
this.nation_confidence_all = nation_confidence_all;
}
public List<?> getBirth_confidence_all() {
return birth_confidence_all;
}
public void setBirth_confidence_all(List<?> birth_confidence_all) {
this.birth_confidence_all = birth_confidence_all;
}
public List<?> getAddress_confidence_all() {
return address_confidence_all;
}
public void setAddress_confidence_all(List<?> address_confidence_all) {
this.address_confidence_all = address_confidence_all;
}
public List<?> getId_confidence_all() {
return id_confidence_all;
}
public void setId_confidence_all(List<?> id_confidence_all) {
this.id_confidence_all = id_confidence_all;
}
public List<?> getFrontimage_confidence_all() {
return frontimage_confidence_all;
}
public void setFrontimage_confidence_all(List<?> frontimage_confidence_all) {
this.frontimage_confidence_all = frontimage_confidence_all;
}
public List<?> getWatermask_confidence_all() {
return watermask_confidence_all;
}
public void setWatermask_confidence_all(List<?> watermask_confidence_all) {
this.watermask_confidence_all = watermask_confidence_all;
}
public List<Integer> getValid_date_confidence_all() {
return valid_date_confidence_all;
}
public void setValid_date_confidence_all(List<Integer> valid_date_confidence_all) {
this.valid_date_confidence_all = valid_date_confidence_all;
}
public List<Integer> getAuthority_confidence_all() {
return authority_confidence_all;
}
public void setAuthority_confidence_all(List<Integer> authority_confidence_all) {
this.authority_confidence_all = authority_confidence_all;
}
public List<?> getBackimage_confidence_all() {
return backimage_confidence_all;
}
public void setBackimage_confidence_all(List<?> backimage_confidence_all) {
this.backimage_confidence_all = backimage_confidence_all;
}
public List<?> getDetail_errorcode() {
return detail_errorcode;
}
public void setDetail_errorcode(List<?> detail_errorcode) {
this.detail_errorcode = detail_errorcode;
}
public List<?> getDetail_errormsg() {
return detail_errormsg;
}
public void setDetail_errormsg(List<?> detail_errormsg) {
this.detail_errormsg = detail_errormsg;
}
public List<?> getRecognize_warn_code() {
return recognize_warn_code;
}
public void setRecognize_warn_code(List<?> recognize_warn_code) {
this.recognize_warn_code = recognize_warn_code;
}
public List<?> getRecognize_warn_msg() {
return recognize_warn_msg;
}
public void setRecognize_warn_msg(List<?> recognize_warn_msg) {
this.recognize_warn_msg = recognize_warn_msg;
}
}
然後需要幾個工具類
第一個bitmap編解碼工具類
package cn.vonce.doer.utils;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Matrix;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Base64;
import android.widget.Toast;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* bitmap編解碼工具類
*/
public class BitMapUtils {
/**
* bitmap轉為base64
*
* @param bitmap
* @return
*/
public static String bitmapToBase64(Bitmap bitmap) {
String result = null;
ByteArrayOutputStream baos = null;
try {
if (bitmap != null) {
baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
baos.flush();
baos.close();
byte[] bitmapBytes = baos.toByteArray();
result = Base64.encodeToString(bitmapBytes, Base64.DEFAULT);
}
} catch (IOException e) {
return "";
} finally {
try {
if (baos != null) {
baos.flush();
baos.close();
}
} catch (IOException e) {
return "";
}
}
return result;
}
/**
* 從SD卡上獲取圖片。如果不存在則返回null</br>
* @return 代表圖片的Bitmap物件
*/
public static Bitmap getBitmapFromSDCard(String url) {
InputStream inputStream = null;
try {
inputStream = new FileInputStream(new File(url));
if (inputStream != null && inputStream.available() > 0) {
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
return bitmap;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// 分享單張圖片
public static void shareSingleImage(Context context, Bitmap copy) {
if(copy != null){
File appDir = new File(Environment.getExternalStorageDirectory(), "demo");
if (!appDir.exists()) {
appDir.mkdir();
}
String fileName = System.currentTimeMillis() + ".jpg";
File file = new File(appDir, fileName);
try {
FileOutputStream fos = new FileOutputStream(file);
copy.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
String path = file.getAbsolutePath();
// 由檔案得到uri
Uri imageUri = Uri.fromFile(new File(path));
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, imageUri);
shareIntent.setType("image/*");
context.startActivity(Intent.createChooser(shareIntent, "分享到"));
}else {
Toast.makeText(context, "請先從相簿選擇一張圖片", Toast.LENGTH_SHORT).show();
}
}
/**
* 儲存圖片到本地相簿
*
* @param context 上下文
* @param bmp 要儲存的bitmap
*/
public static void saveImageToGallery(Context context, Bitmap bmp) {
// 首先儲存圖片
File appDir = new File(Environment.getExternalStorageDirectory(), "demo");
if (!appDir.exists()) {
appDir.mkdir();
}
String fileName = System.currentTimeMillis() + ".jpg";
File file = new File(appDir, fileName);
try {
FileOutputStream fos = new FileOutputStream(file);
bmp.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
String path = file.getAbsolutePath();
// 其次把檔案插入到系統圖庫
try {
MediaStore.Images.Media.insertImage(context.getContentResolver(),
file.getAbsolutePath(), fileName, null);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Toast.makeText(context, "圖片已儲存至" + path, Toast.LENGTH_SHORT).show();
// 最後通知相簿更新
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + path)));
}
/**
* 選擇圖片後壓縮展示
*/
public static Bitmap onSelected(String local_path) {
Bitmap bitmap = BitmapFactory.decodeFile(local_path);
ByteArrayOutputStream out = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 85, out);
int size = bitmap.getWidth() * bitmap.getHeight();
float zoom = (float) Math.sqrt(size * 1024 / (float)out.toByteArray().length);
Matrix matrix = new Matrix();
matrix.setScale(zoom, zoom);
Bitmap result = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
out.reset();
result.compress(Bitmap.CompressFormat.JPEG, 85, out);
while(out.toByteArray().length > size * 1024){
System.out.println(out.toByteArray().length);
matrix.setScale(0.9f, 0.9f);
result = Bitmap.createBitmap(result, 0, 0, result.getWidth(), result.getHeight(), matrix, true);
out.reset();
result.compress(Bitmap.CompressFormat.JPEG, 85, out);
}
bitmap = result;
return bitmap;
}
/**
* 獲取壓縮後的圖片
*
* @param srcPath 要壓縮的圖片路徑
* @return 壓縮後的bitmap
*/
public static Bitmap getImage(String srcPath) {
BitmapFactory.Options newOpts = new BitmapFactory.Options();
// 開始讀入圖片,此時把options.inJustDecodeBounds 設回true了
newOpts.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(srcPath,newOpts);// 此時返回bm為空
newOpts.inJustDecodeBounds = false;
int w = newOpts.outWidth;
int h = newOpts.outHeight;
// 現在主流手機比較多是800*480解析度,所以高和寬我們設定為
float hh = 800f;// 這裡設定高度為800f
float ww = 480f;// 這裡設定寬度為480f
// 縮放比。由於是固定比例縮放,只用高或者寬其中一個數據進行計算即可
int be = 1;// be=1表示不縮放
if (w > h && w > ww) {// 如果寬度大的話根據寬度固定大小縮放
be = (int) (newOpts.outWidth / ww);
} else if (w < h && h > hh) {// 如果高度高的話根據寬度固定大小縮放
be = (int) (newOpts.outHeight / hh);
}
if (be <= 0)
be = 1;
newOpts.inSampleSize = be;// 設定縮放比例
// 重新讀入圖片,注意此時已經把options.inJustDecodeBounds 設回false了
bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
return compressImage(bitmap);// 壓縮好比例大小後再進行質量壓縮
}
public static Bitmap compressImage(Bitmap image) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);// 質量壓縮方法,這裡100表示不壓縮,把壓縮後的資料存放到baos中
int options = 100;
while (baos.toByteArray().length / 1024 > 100) { // 迴圈判斷如果壓縮後圖片是否大於100kb,大於繼續壓縮
baos.reset();// 重置baos即清空baos
image.compress(Bitmap.CompressFormat.JPEG, options, baos);// 這裡壓縮options%,把壓縮後的資料存放到baos中
options -= 10;// 每次都減少10
}
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());// 把壓縮後的資料baos存放到ByteArrayInputStream中
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);// 把ByteArrayInputStream資料生成圖片
return bitmap;
}
/**
* 處理指定的圖片
*/
public static Bitmap handlePicture(Bitmap bitmap){
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Bitmap copy = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
int[] before = new int[width * height];
int[] after = new int[width * height];
bitmap.getPixels(before, 0, width, 0, 0, width, height);
int pixelsA, pixelsR, pixelsG, pixelsB;
for(int i = 0;i < width * height;i++){
int color = before[i];
// ∂獲取RGB分量
pixelsA = Color.alpha(color);
pixelsR = Color.red(color);
pixelsG = Color.green(color);
pixelsB = Color.blue(color);
if(pixelsA >= 1) {
// 轉換
pixelsR = (255 - pixelsR);
pixelsG = (255 - pixelsG);
pixelsB = (255 - pixelsB);
// 均小於等於255大於等於0
if (pixelsR > 255) {
pixelsR = 255;
} else if (pixelsR < 0) {
pixelsR = 0;
}
if (pixelsG > 255) {
pixelsG = 255;
} else if (pixelsG < 0) {
pixelsG = 0;
}
if (pixelsB > 255) {
pixelsB = 255;
} else if (pixelsB < 0) {
pixelsB = 0;
}
}
// 根據新的RGB生成新畫素
after[i] = Color.argb(pixelsA, pixelsR, pixelsG, pixelsB);
}
copy.setPixels(after, 0, width, 0, 0, width, height);
return copy;
}
/**
* 處理指定的圖片為黑白照片
*/
public static Bitmap colored(Bitmap bitmap){
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Bitmap copy = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
int[] before = new int[width * height];
int[] after = new int[width * height];
bitmap.getPixels(before, 0, width, 0, 0, width, height);
int pixelsA, pixelsR, pixelsG, pixelsB;
for(int i = 0;i < width * height;i++){
int color = before[i];
// 獲取RGB分量
pixelsA = Color.alpha(color);
pixelsR = Color.red(color);
pixelsG = Color.green(color);
pixelsB = Color.blue(color);
if(pixelsA >= 1) {
pixelsR = pixelsG = pixelsB = (pixelsR + pixelsG + pixelsB) / 3;
}
// 根據新的RGB生成新畫素
after[i] = Color.argb(pixelsA, pixelsR, pixelsG, pixelsB);
}
copy.setPixels(after, 0, width, 0, 0, width, height);
return copy;
}
/**
* 處理指定的圖片為半透明照片
*/
public static Bitmap halfTrans(Bitmap bitmap){
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Bitmap copy = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
int[] before = new int[width * height];
int[] after = new int[width * height];
bitmap.getPixels(before, 0, width, 0, 0, width, height);
int pixelsA, pixelsR, pixelsG, pixelsB;
for(int i = 0;i < width * height;i++){
int color = before[i];
// 獲取RGB分量
pixelsA = Color.alpha(color);
pixelsR = Color.red(color);
pixelsG = Color.green(color);
pixelsB = Color.blue(color);
// 根據新的RGB生成新畫素
after[i] = Color.argb(pixelsA / 2, pixelsR, pixelsG, pixelsB);
}
copy.setPixels(after, 0, width, 0, 0, width, height);
return copy;
}
}
第二個網路請求工具類 請求騰訊的介面
package cn.vonce.doer.utils;
import android.util.Log;
import org.xutils.common.Callback;
import org.xutils.http.RequestParams;
import org.xutils.x;
import java.io.File;
import cn.vonce.doer.sign.Constant;
import cn.vonce.doer.sign.YoutuSign;
/**
* 網路請求工具類
*/
public class TecentHttpUtil {
public static void uploadIdCard(String bitmap, String card_type, final SimpleCallBack callback) {
StringBuffer mySign = new StringBuffer("");
YoutuSign.appSign(Constant.AppID, Constant.SecretID, Constant.SecretKey,
System.currentTimeMillis() / 1000 + Constant.EXPIRED_SECONDS,
Constant.QQNumber, mySign);
RequestParams params = new RequestParams("http://api.youtu.qq.com/youtu/ocrapi/idcardocr");
params.setAsJsonContent(true);
params.addHeader("accept", "*/*");
params.addHeader("Host", "api.youtu.qq.com");
params.addHeader("user-agent", "youtu-java-sdk");
params.addHeader("Authorization", mySign.toString());
params.addHeader("Content-Type", "text/json");
params.addParameter("card_type", Integer.valueOf(card_type));
params.addBodyParameter("image", bitmap);
params.addBodyParameter("app_id", Constant.AppID);
x.http().post(params, new Callback.CommonCallback<String>() {
@Override
public void onSuccess(String result) {
Log.d("onSuccess",result);
callback.Succ(result);
}
@Override
public void onError(Throwable ex, boolean isOnCallback) {
Log.d("onError",ex.getMessage());
}
@Override
public void onCancelled(CancelledException cex) {
Log.d("onCancelled", cex.getMessage());
}
@Override
public void onFinished() {
}
});
}
public interface SimpleCallBack {
void Succ(String result);
void error();
}
}
在網路請求工具類裡面會用到你申請的id了 需要幾個類
package com.example.aa.demo.sign;
import java.util.Random;
public class YoutuSign {
/**
*app_sign 時效性簽名
*@param appId http://open.youtu.qq.com/上申請的業務ID
*@param secret_id http://open.youtu.qq.com/上申請的金鑰id
*@param secret_key http://open.youtu.qq.com/上申請的金鑰key
*@param expired 簽名過期時間
*@param userid 業務賬號系統,沒有可以不填
*@param mySign 生成的簽名
*@return 0表示成功
*/
public static int appSign(String appId, String secret_id, String secret_key,
long expired, String userid, StringBuffer mySign) {
return appSignBase(appId, secret_id, secret_key, expired, userid, null, mySign);
}
private static int appSignBase(String appId, String secret_id,
String secret_key, long expired, String userid, String url,
StringBuffer mySign) {
if (empty(secret_id) || empty(secret_key))
{
return -1;
}
String puserid = "";
if (!empty(userid))
{
if (userid.length() > 64)
{
return -2;
}
puserid = userid;
}
long now = System.currentTimeMillis() / 1000;
int rdm = Math.abs(new Random().nextInt());
String plain_text = "a=" + appId + "&k=" + secret_id + "&e=" + expired + "&t=" + now + "&r=" + rdm + "&u=" + puserid ;//+ "&f=" + fileid.toString();
byte[] bin = hashHmac(plain_text, secret_key);
byte[] all = new byte[bin.length + plain_text.getBytes().length];
System.arraycopy(bin, 0, all, 0, bin.length);
System.arraycopy(plain_text.getBytes(), 0, all, bin.length, plain_text.getBytes().length);
mySign.append(Base64Util.encode(all));
return 0;
}
private static byte[] hashHmac(String plain_text, String accessKey) {
try {
return HMACSHA1.getSignature(plain_text, accessKey);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static boolean empty(String s){
return s == null || s.trim().equals("") || s.trim().equals("null");
}
}
package com.example.aa.demo.sign;
public class Base64Util {
private static final char last2byte = (char) Integer
.parseInt("00000011", 2);
private static final char last4byte = (char) Integer
.parseInt("00001111", 2);
private static final char last6byte = (char) Integer
.parseInt("00111111", 2);
private static final char lead6byte = (char) Integer
.parseInt("11111100", 2);
private static final char lead4byte = (char) Integer
.parseInt("11110000", 2);
private static final char lead2byte = (char) Integer
.parseInt("11000000", 2);
private static final char[] encodeTable = new char[] { 'A', 'B', 'C', 'D',
'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/' };
/**
* Base64 encoding.
*
* @param from
* The src data.
* @return cryto_str
*/
public static String encode(byte[] from) {
StringBuilder to = new StringBuilder((int) (from.length * 1.34) + 3);
int num = 0;
char currentByte = 0;
for (int i = 0; i < from.length; i++) {
num = num % 8;
while (num < 8) {
switch (num) {
case 0:
currentByte = (char) (from[i] & lead6byte);
currentByte = (char) (currentByte >>> 2);
break;
case 2:
currentByte = (char) (from[i] & last6byte);
break;
case 4:
currentByte = (char) (from[i] & last4byte);
currentByte = (char) (currentByte << 2);
if ((i + 1) < from.length) {
currentByte |= (from[i + 1] & lead2byte) >>> 6;
}
break;
case 6:
currentByte = (char) (from[i] & last2byte);
currentByte = (char) (currentByte << 4);
if ((i + 1) < from.length) {
currentByte |= (from[i + 1] & lead4byte) >>> 4;
}
break;
}
to.append(encodeTable[currentByte]);
num += 6;
}
}
if (to.length() % 4 != 0) {
for (int i = 4 - to.length() % 4; i > 0; i--) {
to.append("=");
}
}
return to.toString();
}
}
package com.example.aa.demo.sign;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class HMACSHA1 {
private static final String HMAC_SHA1 = "HmacSHA1";
public static byte[] getSignature(String data, String key) throws Exception {
Mac mac = Mac.getInstance(HMAC_SHA1);
SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(),
mac.getAlgorithm());
mac.init(signingKey);
return mac.doFinal(data.getBytes());
}
}
package com.example.aa.demo.sign;
/**
* 優圖賬號
*這裡填大家自己申請的
*/
public class Constant {
public static String QQNumber = "";// 騰訊優圖開發者賬號(QQ號)
public static String AppID = "";
public static String SecretID = "";
public static String SecretKey = "";
public static int EXPIRED_SECONDS = ;// 過期時間戳
}
然後就是主類了
package com.example.aa.demo;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;
import com.example.aa.demo.entity.IdentifyResult;
import com.example.aa.demo.entity.cardReverseRusult;
import com.example.aa.demo.utils.BitMapUtils;
import com.example.aa.demo.utils.TecentHttpUtil;
import com.google.gson.Gson;
import com.luck.picture.lib.PictureSelector;
import com.luck.picture.lib.config.PictureConfig;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.entity.LocalMedia;
import java.util.ArrayList;
import java.util.List;
public class AutonymCertificationActivity extends AppCompatActivity implements View.OnClickListener {
/**
* 身份證正面
*/
private ImageView activity_autonym_certification_iv_positive;
/**
* 身份證反面
*/
private ImageView activity_autonym_certification_iv_reverse;
/**
* 選擇身份證正面
*/
private List<LocalMedia> cardPositive = new ArrayList<>();
/**
* 選擇身份證反面
*/
private List<LocalMedia> cardReverse = new ArrayList<>();
/**
* 選擇模式:全部.PictureMimeType.ofAll()、圖片.ofImage()、視訊.ofVideo()、音訊.ofAudio()
*/
private int chooseMode = PictureMimeType.ofImage();
/**
* 主題id:R.style.picture_default_style、R.style.picture_white_style、R.style.picture_QQ_style、R.style.picture_Sina_style
*/
private int themeId = R.style.picture_default_style;
/**
* 最多可選擇1張圖片
*/
private int maxSelectNum = 1;
/**
* 正反圖片路徑
*/
private String cardPositivePath = null, cardReversePath = null;
/**
* 儲存圖片,正反
*/
private Bitmap cardPositiveBitMap, cardReverseBitMap;
/**
* 自動識別姓名 有效日期 身份證號碼
*/
private EditText activity_autonym_certification_et_name;
private EditText activity_autonym_certification_et_effective_date;
private EditText activity_autonym_certification_et_id_card;
/**
* 存放正面識別資料的類
*/
IdentifyResult result;
/**
* 存放反面識別資料的類
*/
cardReverseRusult cardReverseRusult;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_autonym_certification);
//初始化找id
initViews();
}
private void initViews() {
activity_autonym_certification_iv_positive=findViewById(R.id.activity_autonym_certification_iv_positive);
activity_autonym_certification_iv_reverse=findViewById(R.id.activity_autonym_certification_iv_reverse);
activity_autonym_certification_et_name=findViewById(R.id.activity_autonym_certification_et_name);
activity_autonym_certification_et_effective_date=findViewById(R.id.activity_autonym_certification_et_effective_date);
activity_autonym_certification_et_id_card=findViewById(R.id.activity_autonym_certification_et_id_card);
activity_autonym_certification_iv_positive.setOnClickListener(this);
activity_autonym_certification_iv_reverse.setOnClickListener(this);
//簡單的申請兩個許可權
if (ContextCompat.checkSelfPermission(AutonymCertificationActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
1);
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
//身份證正面點選事件
case R.id.activity_autonym_certification_iv_positive:
//0表示正面
OpenPhotoAlbum(cardPositive, 0);
break;
//身份證反面的點選事件 1表示反面
case R.id.activity_autonym_certification_iv_reverse:
OpenPhotoAlbum(cardReverse, 1);
break;
}
}
/**
* @param list 相片返回的地方
* @param i 判斷返回的是正反 0是正面 1是反面
*/
private void OpenPhotoAlbum(List list, int i) {
// 進入相簿 以下是例子:不需要的api可以不寫
PictureSelector.create(this)
.openGallery(chooseMode)// 全部.PictureMimeType.ofAll()、圖片.ofImage()、視訊.ofVideo()、音訊.ofAudio()
.theme(themeId)// 主題樣式設定 具體參考 values/styles 用法:R.style.picture.white.style
.maxSelectNum(maxSelectNum)// 最大圖片選擇數量
.minSelectNum(1)// 最小選擇數量
.imageSpanCount(4)// 每行顯示個數
.selectionMode(PictureConfig.MULTIPLE)// PictureConfig.MULTIPLE多選 or 單選PictureConfig.SINGLE
.previewImage(true)// 是否可預覽圖片
//.previewVideo(true)// 是否可預覽視訊
//.enablePreviewAudio(ture) // 是否可播放音訊
//.compressGrade(Luban.THIRD_GEAR)// luban壓縮檔次,預設3檔 Luban.FIRST_GEAR、Luban.CUSTOM_GEAR
.isCamera(true)// 是否顯示拍照按鈕
.isZoomAnim(true)// 圖片列表點選 縮放效果 預設true
//.setOutputCameraPath("/CustomPath")// 自定義拍照儲存路徑
//.enableCrop(false)// 是否裁剪
.compress(true)// 是否壓縮
// .compressMode(PictureConfig.SYSTEM_COMPRESS_MODE)//系統自帶 or 魯班壓縮 PictureConfig.SYSTEM_COMPRESS_MODE or LUBAN_COMPRESS_MODE
//.sizeMultiplier(0.5f)// glide 載入圖片大小 0~1之間 如設定 .glideOverride()無效
.glideOverride(160, 160)// glide 載入寬高,越小圖片列表越流暢,但會影響列表圖片瀏覽的清晰度
//.withAspectRatio(0, 0)// 裁剪比例 如16:9 3:2 3:4 1:1 可自定義
//.hideBottomControls(false)// 是否顯示uCrop工具欄,預設不顯示
//.isGif(false)// 是否顯示gif圖片
//.freeStyleCropEnabled(false)// 裁剪框是否可拖拽
//.circleDimmedLayer(false)// 是否圓形裁剪
//.showCropFrame(false)// 是否顯示裁剪矩形邊框 圓形裁剪時建議設為false
//.showCropGrid(false)// 是否顯示裁剪矩形網格 圓形裁剪時建議設為false
.openClickSound(false)// 是否開啟點選聲音
.selectionMedia(list)// 是否傳入已選圖片
// .videoMaxSecond(15)
// .videoMinSecond(10)
//.previewEggs(false)// 預覽圖片時 是否增強左右滑動圖片體驗(圖片滑動一半即可看到上一張是否選中)
//.cropCompressQuality(90)// 裁剪壓縮質量 預設100
//.compressMaxKB()//壓縮最大值kb compressGrade()為Luban.CUSTOM_GEAR有效
//.compressWH() // 壓縮寬高比 compressGrade()為Luban.CUSTOM_GEAR有效
//.cropWH()// 裁剪寬高比,設定如果大於圖片本身寬高則無效
//.rotateEnabled() // 裁剪是否可旋轉圖片
//.scaleEnabled()// 裁剪是否可放大縮小圖片
//.videoQuality()// 視訊錄製質量 0 or 1
//.videoSecond()//顯示多少秒以內的視訊or音訊也可適用
//.recordVideoSecond()//錄製視訊秒數 預設60s
.forResult(i);//結果回撥onActivityResult code(這裡自己設定了0.1 目的區分是正反)
}
//選擇完照片的回撥
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//選擇圖片回撥
if (resultCode == RESULT_OK) {
switch (requestCode) {
case 0:
/**
* 正面識別
*/
// 圖片選擇結果回撥
cardPositive = PictureSelector.obtainMultipleResult(data);
// 例如 LocalMedia 裡面返回三種path
// 1.media.getPath(); 為原圖path
// 2.media.getCutPath();為裁剪後path,需判斷media.isCut();是否為true
// 3.media.getCompressPath();為壓縮後path,需判斷media.isCompressed();是否為true
// 如果裁剪並壓縮了,以取壓縮路徑為準,因為是先裁剪後壓縮的
//首先獲取圖片地址
if (cardPositive.size() > 0) {
//首先確保大於0
LocalMedia localMedia = cardPositive.get(0);
cardPositivePath = localMedia.getPath();//正常的地址,看具體的業務,如果需要壓縮,則獲取壓縮地址
//拿到了地址,那麼就載入圖片
cardPositiveBitMap = BitMapUtils.getImage(cardPositivePath);
// //設定圖片
activity_autonym_certification_iv_positive.setImageBitmap(cardPositiveBitMap);
//設定完成自動識別
TecentHttpUtil.uploadIdCard(BitMapUtils.bitmapToBase64(cardPositiveBitMap), "0", new TecentHttpUtil.SimpleCallBack() {
@Override
public void Succ(String res) {
result = new Gson().fromJson(res, IdentifyResult.class);
if (result != null) {
if (result.getErrorcode() == 0) {
// 識別成功設定姓名
activity_autonym_certification_et_name.setText(result.getName());
//設定身份證號碼
activity_autonym_certification_et_id_card.setText(result.getId());
} else {
Toast.makeText(AutonymCertificationActivity.this, "識別錯誤", Toast.LENGTH_SHORT).show();
/*switch (result.getErrorcode()){
case -7001:
Toast.makeText(MainActivity.this, "未檢測到身份證,請對準邊框(請避免拍攝時傾角和旋轉角過大、攝像頭)", Toast.LENGTH_SHORT).show();
break;
case -7002:
Toast.makeText(MainActivity.this, "請使用第二代身份證件進行掃描", Toast.LENGTH_SHORT).show();
break;
case -7003:
Toast.makeText(MainActivity.this, "不是身份證正面照片(請使用帶證件照的一面進行掃描)", Toast.LENGTH_SHORT).show();
break;
case -7004:
Toast.makeText(MainActivity.this, "不是身份證反面照片(請使用身份證反面進行掃描)", Toast.LENGTH_SHORT).show();
break;
case -7005:
Toast.makeText(MainActivity.this, "確保掃描證件影象清晰", Toast.LENGTH_SHORT).show();
break;
case -7006:
Toast.makeText(MainActivity.this, "請避開燈光直射在證件表面", Toast.LENGTH_SHORT).show();
break;
default:
Toast.makeText(MainActivity.this, "識別失敗,請稍後重試", Toast.LENGTH_SHORT).show();
break;
}*/
}
}
}
@Override
public void error() {
Log.i("識別錯誤", "error: ");
}
});
}
break;
case 1:
/**
* 反面識別
*/
cardReverse = PictureSelector.obtainMultipleResult(data);
if (cardReverse.size() > 0) {
//首先確保大於0
LocalMedia localMedia = cardReverse.get(0);
cardReversePath = localMedia.getPath();//正常的地址,看具體的業務,如果需要壓縮,則獲取壓縮地址
//拿到了地址,那麼就載入圖片
cardReverseBitMap = BitMapUtils.getImage(cardReversePath);
// //設定圖片
activity_autonym_certification_iv_reverse.setImageBitmap(cardReverseBitMap);
TecentHttpUtil.uploadIdCard(BitMapUtils.bitmapToBase64(cardReverseBitMap), "1", new TecentHttpUtil.SimpleCallBack() {
@Override
public void Succ(String res) {
Log.e("===========success", res);
cardReverseRusult = new Gson().fromJson(res, cardReverseRusult.class);
if (cardReverseRusult != null) {
if (cardReverseRusult.getErrorcode() == 0) {
//反面識別成功設定有效日期
activity_autonym_certification_et_effective_date.setText(cardReverseRusult.getValid_date());
} else {
Toast.makeText(AutonymCertificationActivity.this, "識別錯誤", Toast.LENGTH_SHORT).show();
}
}
}
@Override
public void error() {
Log.i("識別錯誤", "error: ");
}
});
}
break;
}
}
}
@Override
public void onPointerCaptureChanged(boolean hasCapture) {
}
}
到這來專案基本就跑起來了,程式碼不好,僅供參考,宣告,裡面有一些程式碼是參考了網路上的。