源码下载地址:注:源码里没有腾讯优图的账号需要填写自己的 下载地址
先讲几下.首先我们需要去腾讯优图申请一个账号,因为身份证识别需要用到第三方接口如图所示
我申请的是扫描身份证,当然还有其他的功能,比如扫描银行卡,营业执照,车牌等等 ,大家可以去研究一下
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()
}
}
下面配置好权限
然后新建一个Application配置下网络请求吧
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//网络请求
x.Ext.init(this);
}
}
记得在Manifests中设置一下name=.MyApplication
接下来是布局文件来,等会上代码了
然后是两个实体类用来存放身份证 正反两面的数据,先是正面
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 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> valid_date_confidence_all;
private List> authority_confidence_all;
private List> backimage_confidence_all;
private List detail_errorcode;
private List 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 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> 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 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;
}
}
再是反面
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 valid_date_confidence_all;
private List 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 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> 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
* @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() {
@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 cardPositive = new ArrayList<>();
/**
* 选择身份证反面
*/
private List 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) {
}
}
到这来项目基本就跑起来了,代码不好,仅供参考,声明,里面有一些代码是参考了网络上的。