Android之zxing二维码生成与识别

标签: android 二维码 条形码 zxing
50591人阅读 评论(20) 收藏 举报
分类:

二维码:

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

在代码编制上巧妙的利用构成计算机内部逻辑基础的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


查看评论

ZXing 相册中识别二维码和条形码(直接引用就可以了)

*百度了很久一直没有找到关于相册获取条形码的Demo,真心是醉了,只能苦逼的去自己看 闲话不说直接搞起分析:*核心 1,通过路径转换成bitmp对象 2,再bitmap对象转换成二进制图片(二值...
  • tongzhengtong
  • tongzhengtong
  • 2016-06-27 20:32:53
  • 7266

Android 解析二维码图片

我们项目之前已集成了一个zxing的扫描二维码开源库。现新增需求是将用户存储到相册中的二维码图片识别并解析出来。网上也有很多这样解析的例子,我这篇博客也是在借鉴他们提供的方法之后写出来的,整个解析过程...
  • huang_xiao_yu
  • huang_xiao_yu
  • 2016-12-01 15:52:24
  • 2956

利用ZXing生成二维码

这里需要用到zxing的core.jar包 // 生成QR图 private Bitmap createImage(String text) { try { if (TextUti...
  • kazeik
  • kazeik
  • 2012-12-10 22:01:52
  • 8330

zxing的使用及优化

二维码介绍 zxing项目是谷歌推出的用来识别多种格式条形码的开源项目,项目地址为https://github.com/zxing/zxing,zxing有多个人在维护,覆盖主流编程语言,也是目前还...
  • f820306455
  • f820306455
  • 2017-01-06 13:50:28
  • 26790

android直接从图片中对二维码编码解码

001 package com.google.zxing.client.android; 002    003 import...
  • guozh
  • guozh
  • 2012-03-29 11:30:09
  • 5097

Android快速集成Zxing扫码库

今天为大家介绍的是我的github开源项目ZxingSimplify,一个精简的安卓Zxing扫码库。有了它你将分分钟集成扫码(包括二维码、条形码等)功能。 一.扫码界面 二.使用 1.Gradl...
  • shenyuanqing
  • shenyuanqing
  • 2017-04-25 11:14:17
  • 2985

Android zxing 二维码扫描和生成方法(简单版)

前言二维码大家都见识过,这里就不废话了,直接来干货。步骤 导入依赖 compile 'com.google.zxing:core:3.2.1' //zxing核心依赖 com...
  • D_Russell
  • D_Russell
  • 2017-07-31 14:05:15
  • 4501

Android实战——Zxing实现二维码扫描

教你用Zxing实现二维码扫描 前言: 本篇文章从初学者的角度出发,从一个不知道对二维码扫描怎么下手的工作者,需要一个简单的扫描功能的话,可以阅读该篇文章。作为Google开源框架Zxing,里面...
  • qq_30379689
  • qq_30379689
  • 2016-09-02 10:17:58
  • 23513

第三方ZXing库zxing-android-embedded使用及自定义

一、关于ZXing现在一维码二维码在我们的日常生活中使用如此的广泛,所以拥有扫码功能的APP变得非常普遍,一个安卓APP需要扫码功能就要用到zxing了,zxing是谷歌开源的让开发者更方便使用摄像头...
  • u010618194
  • u010618194
  • 2017-09-08 09:55:06
  • 3119

Android二维码扫描模块可简单集成(基于ZXIng实现)

Android二维码扫描模块可简单集成(基于ZXing实现)
  • M075097
  • M075097
  • 2017-11-14 20:57:42
  • 864
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 85万+
    积分: 7614
    排名: 3545
    博客专栏
    最新评论