Android之zxing二维码生成于识别

时间:2022-11-17 00:21:56

前言

二维码的应用现在随处可见,最近在弄即时通信软件,所以想添加二维码名片功能,所以就大概搜索了一下,目前二维码识别与生成比较常用的就是google老大的zxing,比较成熟、稳定,推荐使用。

zxing的引入可以采用源码或jar包引入的方式:

1、以源码引入
zxing的源码在github上的地址为:https://github.com/zxing/zxing,只需要下载core下面的源码就行;

2、以jar包方式引入
jar包下载地址为:
http://www.java2s.com/Code/Jar/z/Downloadzxing20corejar.htm,同样只需要下载core.jar就行;

生成二维码的方法很简单,如下面代码所示

// 生成QR图
private void createImage(String content) {
try {
// 把输入的文本转为二维码
Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");

BitMatrix bitMatrix = new QRCodeWriter().encode(content,
BarcodeFormat.QR_CODE, QR_WIDTH, QR_HEIGHT, hints);

int[] pixels = new int[QR_WIDTH * QR_HEIGHT];
for (int y = 0; y < QR_HEIGHT; y++) {
for (int x = 0; x < QR_WIDTH; x++) {
if (bitMatrix.get(x, y)) {
pixels[y * QR_WIDTH + x] = 0xff000000;
} else {
pixels[y * QR_WIDTH + x] = 0xffffffff;
}

}
}

Bitmap bitmap = Bitmap.createBitmap(QR_WIDTH, QR_HEIGHT,
Bitmap.Config.ARGB_8888);

bitmap.setPixels(pixels, 0, QR_WIDTH, 0, 0, QR_WIDTH, QR_HEIGHT);
if (bitmap != null) {
resultImageView.setImageBitmap(bitmap);
}

} catch (WriterException e) {
e.printStackTrace();
}
}

获取二维码图片的内容

获取内容方面比较麻烦,zxing中的LuminanceSource不能直接使用,所以需要写一个扩展的子类,用以专门解析二维码图片中的内容,由于上面生产的图片内容采用的是json数据的格式,所以在获取内容时也需要按json解析一下;
我封装的LuminanceSource的子类为RGBLuminanceSource,代码如下:

package com.lanou.zxingdemo;
import java.io.FileNotFoundException;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

import com.google.zxing.LuminanceSource;

public class RGBLuminanceSource extends LuminanceSource {
private final byte[] luminances;

public RGBLuminanceSource(Bitmap bitmap) {
super(bitmap.getWidth(), bitmap.getHeight());
//得到图片的宽高
int width = bitmap.getWidth();
int height = bitmap.getHeight();
//得到图片的像素
int[] pixels = new int[width * height];
//
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
//为了测量纯解码速度,我们将整个图像灰度阵列前面,这是一样的通道
// YUVLuminanceSource在现实应用。
//得到像素大小的字节数
luminances = new byte[width * height];
//得到图片每点像素颜色
for (int y = 0; y < height; y++) {
int offset = y * width;
for (int x = 0; x < width; x++) {
int pixel = pixels[offset + x];
int r = (pixel >> 16) & 0xff;
int g = (pixel >> 8) & 0xff;
int b = pixel & 0xff;
//当某一点三种颜色值相同时,相应字节对应空间赋值为其值
if (r == g && g == b) {
luminances[offset + x] = (byte) r;
}
//其它情况字节空间对应赋值为:
else {
luminances[offset + x] = (byte) ((r + g + g + b) >> 2);
}
}
}
}

public RGBLuminanceSource(String path) throws FileNotFoundException {
this(loadBitmap(path));
}


@Override
public byte[] getMatrix() {
return luminances;
}

@Override
public byte[] getRow(int arg0, byte[] arg1) {
if (arg0 < 0 || arg0 >= getHeight()) {
throw new IllegalArgumentException(
"Requested row is outside the image: " + arg0);
}
int width = getWidth();
if (arg1 == null || arg1.length < width) {
arg1 = new byte[width];
}
System.arraycopy(luminances, arg0 * width, arg1, 0, width);
return arg1;
}

private static Bitmap loadBitmap(String path) throws FileNotFoundException {
Bitmap bitmap = BitmapFactory.decodeFile(path);
if (bitmap == null) {
throw new FileNotFoundException("Couldn't open " + path);
}
return bitmap;
}
}

解析二维码内容的方法,代码如下:

// 解析QR图片
private void scanningImage() {
BitmapDrawable drawable = (BitmapDrawable) resultImageView.getDrawable();
if (drawable == null) {
Toast.makeText(this, "还没有图片,请先生成", Toast.LENGTH_LONG).show();
return;
}
Bitmap bitmap = drawable.getBitmap();

Map<DecodeHintType, String> hints = new HashMap<DecodeHintType, String>();
hints.put(DecodeHintType.CHARACTER_SET, "utf-8");

// 获得待解析的图片
RGBLuminanceSource source = new RGBLuminanceSource(bitmap);
BinaryBitmap bitmap1 = new BinaryBitmap(new HybridBinarizer(source));
QRCodeReader reader = new QRCodeReader();
Result result;
try {
result = reader.decode(bitmap1, hints);
JSONObject json = new JSONObject(result.getText());
// 得到解析后的文字
String str =" name: "+json.getString("name")+" \n\r title: "+json.getString("title")+" \n\r url: "+json.getString("url");
resultTv.setText(str);

} catch (NotFoundException e) {
e.printStackTrace();
} catch (ChecksumException e) {
e.printStackTrace();
} catch (FormatException e) {
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

本demo就建了两个java类(MainActivity,RGBLuminanceSource),一个布局文件(activity_main.xml),引入了一个jar包(zxing-core-2.0.jar),完整代码如下:

MainActivity

package com.lanou.zxingdemo;

import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

import org.json.JSONException;
import org.json.JSONObject;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.ChecksumException;
import com.google.zxing.DecodeHintType;
import com.google.zxing.EncodeHintType;
import com.google.zxing.FormatException;
import com.google.zxing.NotFoundException;
import com.google.zxing.Result;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import com.google.zxing.qrcode.QRCodeWriter;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity implements OnClickListener {
private Button encodeBtn,decodeBtn;
private final int QR_WIDTH = 200, QR_HEIGHT = 200;
private ImageView resultImageView;
private TextView resultTv;

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}

private void initView() {
encodeBtn = (Button) findViewById(R.id.encodeBtn);
decodeBtn = (Button) findViewById(R.id.decodeBtn);
encodeBtn.setOnClickListener(this);
decodeBtn.setOnClickListener(this);

resultImageView = (ImageView) findViewById(R.id.resultImageView);
resultTv = (TextView) findViewById(R.id.resultTv);

}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.encodeBtn:

JSONObject json = new JSONObject();
try {
json.put("name", "xiaoxiao");
json.put("url", "http://www.baidu.com");
json.put("title", "title");

createImage(json.toString());

} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
case R.id.decodeBtn:
scanningImage();
break;
}
}

// 生成QR图
private void createImage(String content) {
try {
// 把输入的文本转为二维码
Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");

BitMatrix bitMatrix = new QRCodeWriter().encode(content,
BarcodeFormat.QR_CODE, QR_WIDTH, QR_HEIGHT, hints);

int[] pixels = new int[QR_WIDTH * QR_HEIGHT];
for (int y = 0; y < QR_HEIGHT; y++) {
for (int x = 0; x < QR_WIDTH; x++) {
if (bitMatrix.get(x, y)) {
pixels[y * QR_WIDTH + x] = 0xff000000;
} else {
pixels[y * QR_WIDTH + x] = 0xffffffff;
}

}
}

Bitmap bitmap = Bitmap.createBitmap(QR_WIDTH, QR_HEIGHT,
Bitmap.Config.ARGB_8888);

bitmap.setPixels(pixels, 0, QR_WIDTH, 0, 0, QR_WIDTH, QR_HEIGHT);
if (bitmap != null) {
resultImageView.setImageBitmap(bitmap);
}

} catch (WriterException e) {
e.printStackTrace();
}
}

// 解析QR图片
private void scanningImage() {
BitmapDrawable drawable = (BitmapDrawable) resultImageView.getDrawable();
if (drawable == null) {
Toast.makeText(this, "还没有图片,请先生成", Toast.LENGTH_LONG).show();
return;
}
Bitmap bitmap = drawable.getBitmap();

Map<DecodeHintType, String> hints = new HashMap<DecodeHintType, String>();
hints.put(DecodeHintType.CHARACTER_SET, "utf-8");

// 获得待解析的图片
RGBLuminanceSource source = new RGBLuminanceSource(bitmap);
BinaryBitmap bitmap1 = new BinaryBitmap(new HybridBinarizer(source));
QRCodeReader reader = new QRCodeReader();
Result result;
try {
result = reader.decode(bitmap1, hints);
JSONObject json = new JSONObject(result.getText());
// 得到解析后的文字
String str =" name: "+json.getString("name")+" \n\r title: "+json.getString("title")+" \n\r url: "+json.getString("url");
resultTv.setText(str);

} catch (NotFoundException e) {
e.printStackTrace();
} catch (ChecksumException e) {
e.printStackTrace();
} catch (FormatException e) {
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="${relativePackage}.${activityClass}" >


<LinearLayout
android:id="@+id/linear"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >


<Button
android:id="@+id/encodeBtn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="生成二维码图片" />


<Button
android:id="@+id/decodeBtn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="解析二维码图片中的内容" />

</LinearLayout>

<ImageView
android:id="@+id/resultImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/linear" />


<TextView
android:id="@+id/resultTv"
android:layout_marginTop="30dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/resultImageView" />


</RelativeLayout>

代码结构:

Android之zxing二维码生成于识别

运行效果:

Android之zxing二维码生成于识别