1.概述
中国的二维码技术领先全世界,走在大街上,都是二维码的身影,也极大的方便了我们的生活。今天我们就来讲一讲Android开发中二维码的开发与使用。二维码的功能中包括三大部分,第一是二维码的扫描,比如你微信支付,支付宝支付都需要扫描二维码,第二个是二维码的识别,微信中有这样一个功能,长按一张图片可以弹出识别图中二维码的界面,识别后可以跳转相应页面,第三个是二维码的生成,没有生成哪来的扫描呢,生成就是顾名思义,把你想让别人知道的链接或内容生成对应的二维码供别人扫描。
先看几张最后的效果图吧:
好了,看完最后的效果图我们要说一下怎么实现这些功能了,其实这个里面的原理就是把你传过来的string字符串一生成一个像素一个像素的点,最后组合起来。识别生成也是同样的道理,只不过是反向的逻辑罢了。扫描的时候需要调用相机,别忘了开启相机权限,6.0以上还要做权限适配哟。
2.实现过程及核心代码
1.二维码扫描
现在build.gradle中添加 compile 'com.google.zxing:core:3.1.0' 引入二维码功能需要依赖的包。
扫描的主页面采用surfaceView绘制。加入相机自动对焦方法
/**
* 开始扫描二维码
*/
public void startScanQr() {
// if(cameraManager == null){
cameraManager = new CameraManager(getApplication());
// }
handler = null;
if (isHasSurface) {
initCamera(scanPreview.getHolder());
} else {
scanPreview.getHolder().addCallback(this);
}
inactivityTimer.onResume();
scanLine.startAnimation(animation);
}
private void initCamera(SurfaceHolder surfaceHolder) {
if (surfaceHolder == null) {
throw new IllegalStateException("No SurfaceHolder provided");
}
if (cameraManager.isOpen()) {
return;
}
try {
cameraManager.openDriver(surfaceHolder);
if (handler == null) {
handler = new CaptureActivityHandler(mQrScanListener, cameraManager, DecodeThread.ALL_MODE);
}
initCrop();
} catch (IOException ioe) {
displayFrameworkBugMessageAndExit();
} catch (RuntimeException e) {
displayFrameworkBugMessageAndExit();
}
}
private void handleDecode(final Result rawResult, Bundle bundle) {
inactivityTimer.onActivity();
//震动
vibrate();
handler.postDelayed(new Runnable() {
@Override
public void run() {
Toast.makeText(ScanQRActivity.this, rawResult.getText(), Toast.LENGTH_SHORT).show();
startScanQr();
}
}, 100);
}
private IQrScanCallback mQrScanListener = new IQrScanCallback() {
@Override
public Handler onGetHandler() {
return handler;
}
@Override
public Camera.Size onGetCameraPreviewSize() {
return cameraManager.getPreviewSize();
}
@Override
public Rect onGetCropRect() {
return mCropRect;
}
@Override
public void onHandleDecode(Result result, Bundle bundle) {
handleDecode(result, bundle);
}
@Override
public void onSetScanResult(int activityResult, Intent intent) {
setResult(Activity.RESULT_OK, intent);
finish();
}
};
通过这几个方法拿到Result的text也就是字符串。
2.二维码识别功能实现
/**
* 根据图片路径识别二维码
*
* @param path
* @return
*/
protected Result scanningImage(String path) {
if (TextUtils.isEmpty(path)) {
return null;
}
Hashtable<DecodeHintType, String> hints = new Hashtable<>();
hints.put(DecodeHintType.CHARACTER_SET, "utf-8"); // 设置二维码内容的编码
// boolean isUrlPath = Util.adjustIsURL(path);// 是否为网络地址
// if (isUrlPath) { // 是网络图片
mScanBitmap = getBitmapFromUrl(path);
// } else { // 是本地图片
// mScanBitmap = getBitmapFromUrl(path);
// }
if (mScanBitmap == null) {
return null;
}
int width = mScanBitmap.getWidth();
int height = mScanBitmap.getHeight();
int[] data = new int[width * height];
mScanBitmap.getPixels(data, 0, width, 0, 0, width, height);
Result result = null;
RGBLuminanceSource source = new RGBLuminanceSource(width, height, data);
BinaryBitmap bitmap1 = new BinaryBitmap(new HybridBinarizer(source));
QRCodeReader reader = new QRCodeReader();
try {
result = reader.decode(bitmap1, hints);
} catch (NotFoundException e) {
e.printStackTrace();
} catch (ChecksumException e) {
e.printStackTrace();
} catch (FormatException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
}
return result;
}
/**
* 根据图片的url路径获得Bitmap对象
*
* @param url
* @return
*/
private Bitmap getBitmapFromUrl(String url) {
Bitmap bitmap = null;
try {
bitmap = Glide.with(this).load(url).asBitmap().into(300, 300).get();
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
通过图片的path生成一个bitmap,对这个bitmap进行解析,从而生成result返回。原理也是一个像素一个像素点的解析。当然了跟扫描的过程是一样的,都是耗时操作,所以都需要在子线程中进行操作,result通过handler返回到主线程。
3.二维码的生成
/** 二维码工具类
*/
public class QrCodeUtil {
/**
* 生成二维码Bitmap
*
* @param data 文本内容
* @param size 二维码宽高
* @return 合成后的bitmap
*/
public static Bitmap createQRImage(String data, int size) {
if (size <= 0 || size <= 0) {
size = 400;
}
try {
if (data == null || data.length() == 0) {
return null;
}
//配置参数
Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
//容错级别
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
//设置空白边距的宽度
hints.put(EncodeHintType.MARGIN, 0); //default is 4
// 图像数据转换,使用了矩阵转换
BitMatrix bitMatrix = new QRCodeWriter().encode(data, BarcodeFormat.QR_CODE, size, size, hints);
int[] pixels = new int[size * size];
// 下面这里按照二维码的算法,逐个生成二维码的图片,
// 两个for循环是图片横列扫描的结果
for (int y = 0; y < size; y++) {
for (int x = 0; x < size; x++) {
if (bitMatrix.get(x, y)) {
pixels[y * size + x] = 0xff000000;
} else {
pixels[y * size + x] = 0xffffffff;
}
}
}
// 生成二维码图片的格式,使用ARGB_8888
Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.RGB_565);
bitmap.setPixels(pixels, 0, size, 0, 0, size, size);
return bitmap;
//必须使用compress方法将bitmap保存到文件中再进行读取。直接返回的bitmap是没有任何压缩的,内存消耗巨大!
//return bitmap != null && bitmap.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(filePath));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 生成带logo的二维码,logo默认为二维码的1/10
*
* @param text 需要生成二维码的文字、网址等
* @param mBitmap logo文件
* @param size 需要生成二维码的大小()
* @return bitmap
*/
public static Bitmap createQRCodeWithLogo(String text, Bitmap mBitmap, int size) {
try {
int logoImageHalfSize = size / 10;
Hashtable<EncodeHintType, Object> hints = new Hashtable<>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
/*
* 设置容错级别,默认为ErrorCorrectionLevel.L
* 因为中间加入logo所以建议你把容错级别调至H,否则可能会出现识别不了
*/
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
//设置空白边距的宽度
hints.put(EncodeHintType.MARGIN, 0); //default is 4
BitMatrix bitMatrix = new QRCodeWriter().encode(text, BarcodeFormat.QR_CODE, size, size, hints);
int width = bitMatrix.getWidth();//矩阵高度
int height = bitMatrix.getHeight();//矩阵宽度
int halfW = width / 2;
int halfH = height / 2;
Matrix m = new Matrix();
float sx = (float) 2 * logoImageHalfSize / mBitmap.getWidth();
float sy = (float) 2 * logoImageHalfSize / mBitmap.getHeight();
m.setScale(sx, sy);
//设置缩放信息
//将logo图片按martix设置的信息缩放
mBitmap = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(), mBitmap.getHeight(), m, false);
int[] pixels = new int[size * size];
for (int y = 0; y < size; y++) {
for (int x = 0; x < size; x++) {
if (x > halfW - logoImageHalfSize && x < halfW + logoImageHalfSize && y > halfH - logoImageHalfSize
&& y < halfH + logoImageHalfSize) {
//该位置用于存放图片信息
//记录图片每个像素信息
pixels[y * width + x] = mBitmap.getPixel(x - halfW + logoImageHalfSize, y - halfH + logoImageHalfSize);
} else {
if (bitMatrix.get(x, y)) {
pixels[y * size + x] = 0xff000000;
} else {
pixels[y * size + x] = 0xffffffff;
}
}
}
}
Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, size, 0, 0, size, size);
return bitmap;
} catch (WriterException e) {
e.printStackTrace();
return null;
}
}
}
先贴最主要代码,这个工具类有两个方法,一个是通过String生成最普通的二维码,第二个是通过String,bitmap生成带logo的二维码(这个比较常见,我们生活中的二维码很多都是这样的).
这样就完全可以集成二维码三大功能了,最底层的代码都是骨灰级别的人物写的,我们只需要会调用就可以了.好了,这些干货带给大家,以后项目中如果需要二维码相关功能可以借鉴一下。
需要完整代码的可以在下面留言邮箱地址,请叫我雷锋。