Android之zxing二维码生成与识别

二维码:

是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的;

在代码编制上巧妙的利用构成计算机内部逻辑基础的0和1比特流的概念,使用若干个与二进制相对应的几何形体来表示文字数值信息,通过图像输入设备或光电扫描设备自动识读以实现信息自动处理;

二维码能够在横向和纵向两个方位同时表达信息,因此能在很小的面积内表达大量的信息;

二维码相对于条形码的优势就是省空间;

 

zxing简介:

zxing是一个开放源码的,用java实现的多种格式的1D/2D条码图像处理库,它包含了联系到其他语言的接口。

zxing可以实现使用手机的内置的摄像头完成条形码和二维码的扫描与解码。

zxing可以实现条形码和二维码的编码与解码。

zxing目前支持的的格式如下:

UPC-A,UPC-E

EAN-8,EAN-13

39码

93码

代码128

QR码

 

Android上zxing的使用:

这里使用的时候可以有两种形式:

1.将zxing的jar包放到工程的lib库中,然后还要拷贝相应的类源码到工程中去,整个文件夹拷贝过去也是很快的;

2.将已经弄好zxing的工程作为当前工程的依赖库,然后直接使用就可以了;

如图:

 

 

下面来通过一个实例来完成以下三个功能:

1.生成二维码;

2.解析二维码图片;

3.扫描二维码并解析;

 

最终效果是这样的:

 

在我们新建工程之前,我们必须将依赖库导入到Eclipse中,依赖库的原工程文件夹我已经打包,文章最后面有链接可以下载。

 

识别二维码(识别图片)这个功能需要用到一个名叫RGBLuminanceSource的类,这个类的内容如下:

 

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;
	}
}


接下来,还有一个特别要注意的地方就是manifest的配置部分,需要加入权限,和依赖库中的一个Activity的声明:

 

 

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name="com.zxing.activity.CaptureActivity"></activity>
    </application>


好,现在我们来看看自己编写的Activity类如何实现以上所说的三个功能:

 

 

import java.util.Hashtable;

import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import com.zxing.activity.CaptureActivity;
import com.zxing.encoding.EncodingHandler;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends Activity implements OnClickListener {
	
	private static final int CHOOSE_PIC = 0;
	private static final int PHOTO_PIC = 1;

	private EditText contentEditText = null;
	private ImageView qrcodeImageView = null;
	private String  imgPath = null;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		setupViews();
	}

	private void setupViews() {
		contentEditText = (EditText) findViewById(R.id.editText1);
		findViewById(R.id.button1).setOnClickListener(this);
		findViewById(R.id.button2).setOnClickListener(this);
		findViewById(R.id.button3).setOnClickListener(this);
		qrcodeImageView = (ImageView) findViewById(R.id.img1);
	}
	
	//解析二维码图片,返回结果封装在Result对象中
	private com.google.zxing.Result  parseQRcodeBitmap(String bitmapPath){
		//解析转换类型UTF-8
		Hashtable<DecodeHintType, String> hints = new Hashtable<DecodeHintType, String>();
		hints.put(DecodeHintType.CHARACTER_SET, "utf-8");
		//获取到待解析的图片
		BitmapFactory.Options options = new BitmapFactory.Options(); 
		//如果我们把inJustDecodeBounds设为true,那么BitmapFactory.decodeFile(String path, Options opt)
		//并不会真的返回一个Bitmap给你,它仅仅会把它的宽,高取回来给你
		options.inJustDecodeBounds = true;
		//此时的bitmap是null,这段代码之后,options.outWidth 和 options.outHeight就是我们想要的宽和高了
		Bitmap bitmap = BitmapFactory.decodeFile(bitmapPath,options);
		//我们现在想取出来的图片的边长(二维码图片是正方形的)设置为400像素
		/**
			options.outHeight = 400;
			options.outWidth = 400;
			options.inJustDecodeBounds = false;
			bitmap = BitmapFactory.decodeFile(bitmapPath, options);
		*/
		//以上这种做法,虽然把bitmap限定到了我们要的大小,但是并没有节约内存,如果要节约内存,我们还需要使用inSimpleSize这个属性
		options.inSampleSize = options.outHeight / 400;
		if(options.inSampleSize <= 0){
			options.inSampleSize = 1; //防止其值小于或等于0
		}
		/**
		 * 辅助节约内存设置
		 * 
		 * options.inPreferredConfig = Bitmap.Config.ARGB_4444;    // 默认是Bitmap.Config.ARGB_8888
		 * options.inPurgeable = true; 
		 * options.inInputShareable = true; 
		 */
		options.inJustDecodeBounds = false;
		bitmap = BitmapFactory.decodeFile(bitmapPath, options); 
		//新建一个RGBLuminanceSource对象,将bitmap图片传给此对象
		RGBLuminanceSource rgbLuminanceSource = new RGBLuminanceSource(bitmap);
		//将图片转换成二进制图片
		BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(rgbLuminanceSource));
		//初始化解析对象
		QRCodeReader reader = new QRCodeReader();
		//开始解析
		Result result = null;
		try {
			result = reader.decode(binaryBitmap, hints);
		} catch (Exception e) {
			// TODO: handle exception
		}
		
		return result;
	}
	
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		imgPath = null;
		if(resultCode == RESULT_OK){
			switch (requestCode) {
			case CHOOSE_PIC:
				String[] proj = new String[]{MediaStore.Images.Media.DATA};
				Cursor cursor = MainActivity.this.getContentResolver().query(data.getData(), proj, null, null, null);
				
				if(cursor.moveToFirst()){
					int columnIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
					System.out.println(columnIndex);
					//获取到用户选择的二维码图片的绝对路径
					imgPath = cursor.getString(columnIndex);
				}
				cursor.close();
				
				//获取解析结果
				Result ret = parseQRcodeBitmap(imgPath);
				Toast.makeText(MainActivity.this,"解析结果:" + ret.toString(), Toast.LENGTH_LONG).show();
				break;
			case PHOTO_PIC:
				String result = data.getExtras().getString("result");
				Toast.makeText(MainActivity.this,"解析结果:" + result, Toast.LENGTH_LONG).show();
				break;

			default:
				break;
			}
		}
		
	}
	
	@SuppressLint("InlinedApi")
	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.button1:
			//获取界面输入的内容
			String content = contentEditText.getText().toString();
			//判断内容是否为空
			if (null == content || "".equals(content)) {
				Toast.makeText(MainActivity.this, "请输入要写入二维码的内容...",
						Toast.LENGTH_SHORT).show();
				return;
			}
			
			try {
				//生成二维码图片,第一个参数是二维码的内容,第二个参数是正方形图片的边长,单位是像素
				Bitmap qrcodeBitmap = EncodingHandler.createQRCode(content, 400);
				qrcodeImageView.setImageBitmap(qrcodeBitmap);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			break;
		case R.id.button2:
			//跳转到图片选择界面去选择一张二维码图片
			Intent intent1 = new Intent();
//			if(android.os.Build.VERSION.SDK_INT < 19){
//				intent1.setAction(Intent.ACTION_GET_CONTENT);
//			}else{
//				intent1.setAction(Intent.ACTION_OPEN_DOCUMENT);
//			}
			intent1.setAction(Intent.ACTION_PICK);
			
			intent1.setType("image/*");
			
			Intent intent2 =  Intent.createChooser(intent1, "选择二维码图片");
			startActivityForResult(intent2, CHOOSE_PIC);
			break;
		case R.id.button3:
			//跳转到拍照界面扫描二维码
			Intent intent3 = new Intent(MainActivity.this, CaptureActivity.class);
			startActivityForResult(intent3, PHOTO_PIC);
			break;

		default:
			break;
		}

	}
}


最后附上所有代码打包的链接,有需要的同学可以下载,导入到自己的Eclipse中去:

 

Android Zxing Demo

 

  • 28
    点赞
  • 84
    收藏
    觉得还不错? 一键收藏
  • 20
    评论
如果使用zxing生成的二维码中包含中文字符,那么在扫描二维码时可能会出现识别不了中文的情况。这是因为zxing默认使用ISO-8859-1编码,而中文字符需要使用UTF-8编码。 为了解决这个问题,您可以在生成二维码时将数据字符串转换为UTF-8编码。例如: ``` String data = "你好,世界!"; int width = 500; int height = 500; BitMatrix bitMatrix = new MultiFormatWriter().encode(new String(data.getBytes("UTF-8"), "ISO-8859-1"), BarcodeFormat.QR_CODE, width, height); BarcodeEncoder barcodeEncoder = new BarcodeEncoder(); Bitmap bitmap = barcodeEncoder.createBitmap(bitMatrix); ``` 在这个例子中,我们将数据字符串从UTF-8编码转换为ISO-8859-1编码,然后再生成二维码。这样就可以在扫描二维码时正确识别中文字符了。 同样,在扫描二维码时,您需要确保使用UTF-8编码来解码二维码数据。例如: ``` @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data); if (result != null) { if (result.getContents() == null) { Log.d(TAG, "Cancelled scan"); } else { try { String utf8String = new String(result.getContents().getBytes("ISO-8859-1"), "UTF-8"); Log.d(TAG, "Scanned: " + utf8String); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } } else { super.onActivityResult(requestCode, resultCode, data); } } ``` 在这个例子中,我们首先将二维码数据从ISO-8859-1编码转换为UTF-8编码,然后再处理扫描结果。这样就可以正确识别包含中文字符的二维码了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值