Android之二维码生成与扫描

Posted IT界的吉祥物

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android之二维码生成与扫描相关的知识,希望对你有一定的参考价值。

转载请标明出处:
http://blog.csdn.net/hai_qing_xu_kong/article/details/51260428
本文出自:【顾林海的博客】

##前言

月底离开公司,准备月底休息一段时间,之前每天忙于工作,甚至连一些感兴趣的东西都没有研究过,趁着这段时间可以好好享受一下,今天这篇文章主要描述二维码的生成与扫描,使用目前流行的Zxing,底部会给出整个项目的gitHub地址,为什么要讲二维码,因为二维码太普遍了,随便一个APP都会有二维码扫描。

##Zxing使用

从底部gitHub项目下载地址下载项目完后,可以看到整体代码结构如下:

我们只需将zxing包下的所有代码copy一份到我们的项目中去,除了这写代码以外,还需要zxing的jar包,也从项目中直接copy一份

全部copy完之后,还需要相应的资源文件

1、values文件下的ids文件
2、raw文件中的资源文件(可以替换)
3、layout文件下的activity_capture.xml(可以进行相应的订制)
4、图片资源

##生成二维码

等上面工作全部准备完毕后,就可以创建我们的二维码了,如何生成二维码?这时需要EncodingUtils这个二维码生成工具类。通过调用工具类中的createQRCode方法来生成二维码。

public static Bitmap createQRCode(String content, int widthPix, int heightPix, Bitmap logoBm)

createQRCode方法参数如下:

content:二维码内容
widthPix:二维码宽度
heightPix:二维码高度
logoBm:二维码中间的logo

	/**
	 * 创建二维码并将图片保存在本地
	 */
	private void create() 
		int width = DensityUtil.dip2px(this, 200);
		Bitmap bitmap = EncodingUtils.createQRCode("http://www.baidu.com",
				width, width, BitmapFactory.decodeResource(getResources(),
						R.drawable.ic_launcher));
		iv_zxing.setImageBitmap(bitmap);
		saveBitmap(bitmap);
	

	/**
	 * 将Bitmap保存在本地
	 * 
	 * @param bitmap
	 */
	public void saveBitmap(Bitmap bitmap) 
		// 首先保存图片
		File appDir = new File(Environment.getExternalStorageDirectory(),
				"zxing_image");
		if (!appDir.exists()) 
			appDir.mkdir();
		
		String fileName = "zxing_image" + ".jpg";
		File file = new File(appDir, fileName);
		try 
			FileOutputStream fos = new FileOutputStream(file);
			bitmap.compress(CompressFormat.JPEG, 100, fos);
			fos.flush();
			fos.close();
		 catch (FileNotFoundException e) 
			e.printStackTrace();
		 catch (IOException e) 
			e.printStackTrace();
		

		// 把文件插入到系统图库
		try 
			MediaStore.Images.Media.insertImage(this.getContentResolver(),
					file.getAbsolutePath(), fileName, null);
		 catch (FileNotFoundException e) 
			e.printStackTrace();
		
		// 通知图库更新
		sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
				Uri.parse("file://" + "/sdcard/namecard/")));
	

这里生成的二维码内容是一个百度的地址,中间LOGO是默认的安卓小机器人。

运行程序可以看到如下效果:

##二维码扫描

二维码扫描需要借助于我们的CaptureActivity这个类,打开CaptureActivity界面并进行扫描,扫描完毕后回调onActivityResult方法,也就是我们可以通过onActivityResult得到扫描后的结果。详细代码如下:

	/**
	 * 打开二维码扫描
	 */
	private void open() 
		config();
		startActivityForResult(new Intent(MainActivity.this,
				CaptureActivity.class), 0);
	
	/**
	 * 提高屏幕亮度
	 */
	private void config() 
		WindowManager.LayoutParams lp = getWindow().getAttributes();
		lp.screenBrightness = 1.0f;
		getWindow().setAttributes(lp);
	
	
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) 
		super.onActivityResult(requestCode, resultCode, data);
		if (resultCode == RESULT_OK) 
			Bundle bundle = data.getExtras();
			String result = bundle.getString("result");
			tv_result.setText(result);
		
	

效果就不演示的,因为使用的是模拟器。

##扫描本地图片

扫描本地图片需要我们在CaptureActivity中进行相应的修改,为此我在扫描界面底部增加了一个按钮,用来选择本地图片。layout代码这里就不展示,我们直接看点击后的事件处理。

	/**
	 * 打开本地图片
	 */
	private void openLocalImage() 
		// 打开手机中的相册
		Intent innerIntent = new Intent(Intent.ACTION_GET_CONTENT); 
		innerIntent.setType("image/*");
		Intent wrapperIntent = Intent.createChooser(innerIntent, "选择二维码图片");
		this.startActivityForResult(wrapperIntent, 0x01);
	

打开系统图片库后选择图片,这时需要重写onActivityResult方法用于返回图片信息。

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) 
		super.onActivityResult(requestCode, resultCode, data);
		if (resultCode == RESULT_OK) 
			switch (requestCode) 
			case 0x01:
				// 获取选中图片的路径
				Cursor cursor = getContentResolver().query(data.getData(),
						null, null, null, null);
				if (cursor.moveToFirst()) 
					photo_path = cursor.getString(cursor
							.getColumnIndex(MediaStore.Images.Media.DATA));
				
				cursor.close();

				new Thread(new Runnable() 
					@Override
					public void run() 
						Result result = scanningImage(photo_path);
						if (result != null) 
							handleDecode(result, new Bundle());
						
					
				).start();

				break;

			
		
	

获取图片路径photo_path后,调用scanningImage方法进行扫描,zxing源码中,扫描到的结果都是存放在Result这个结果集中。获取到Result后,就进行结果的回传,阅读CaptureActivity源码,可以得知最后Result结果集会传递给handleDecode方法。

	/**
	 * A valid barcode has been found, so give an indication of success and show
	 * the results.
	 * 
	 * @param rawResult
	 *            The contents of the barcode.
	 * @param bundle
	 *            The extras
	 */
	public void handleDecode(Result rawResult, Bundle bundle) 
		inactivityTimer.onActivity();
		beepManager.playBeepSoundAndVibrate();

		Intent resultIntent = new Intent();
		bundle.putInt("width", mCropRect.width());
		bundle.putInt("height", mCropRect.height());
		bundle.putString("result", rawResult.getText());
		resultIntent.putExtras(bundle);
		this.setResult(RESULT_OK, resultIntent);
		CaptureActivity.this.finish();
	

获取到图片路径后需要将其二维码信息包装成Result对象,因此需要解析图片:

	/**
	 * 扫描二维码图片的方法
	 * 
	 * @param path
	 * @return
	 */
	public Result scanningImage(String path) 
		if (TextUtils.isEmpty(path)) 
			return null;
		
		Hashtable<DecodeHintType, String> hints = new Hashtable<DecodeHintType, String>();
		hints.put(DecodeHintType.CHARACTER_SET, "UTF8"); // 设置二维码内容的编码

		BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true; // 先获取原大小
		scanBitmap = BitmapFactory.decodeFile(path, options);
		options.inJustDecodeBounds = false; // 获取新的大小
		int sampleSize = (int) (options.outHeight / (float) 200);
		if (sampleSize <= 0)
			sampleSize = 1;
		options.inSampleSize = sampleSize;
		scanBitmap = BitmapFactory.decodeFile(path, options);
		int width = scanBitmap.getWidth();
		int height = scanBitmap.getHeight();
		int[] pixels = new int[width * height];
		scanBitmap.getPixels(pixels, 0, width, 0, 0, width, height);
		/**
		 * 第三个参数是图片的像素
		 */
		RGBLuminanceSource source = new RGBLuminanceSource(width, height,
				pixels);
		BinaryBitmap bitmap1 = new BinaryBitmap(new HybridBinarizer(source));
		QRCodeReader reader = new QRCodeReader();
		try 
			return reader.decode(bitmap1, hints);

		 catch (NotFoundException e) 
			e.printStackTrace();
		 catch (ChecksumException e) 
			e.printStackTrace();
		 catch (FormatException e) 
			e.printStackTrace();
		
		return null;
	

根据路径获取Bitmap,最后通过QRCodeReader 中的decode方法解析成Result对象并返回,最终传递给handleDecode方法。

运行程序效果如下:

最后扫描出来的是之前定义的百度地址。

##权限与Activity

当二维码的生成与扫描完成后,别忘了权限:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.zxingtest"
    android:versionCode="1"
    android:versionName="1.0" >
    
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
    
    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.VIBRATE"/>

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="17" />

    <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.example.zxingtest.zxing.activity.CaptureActivity"></activity>
    </application>

</manifest>

以下是完整的github项目地址
github项目源码地址:点击【项目源码】

以上是关于Android之二维码生成与扫描的主要内容,如果未能解决你的问题,请参考以下文章

玩转Android之二维码生成与识别

Android之扫描二维码和根据输入信息生成名片二维码

Android开发之扫描二维码开发

iOS7后 苹果 二维码生成与扫描

Android基于Google Zxing实现二维码/条形码扫描生成二维码/条形码

android 生成的二维码图片如何保存到sdcard? 这个我也不知道呢,能否告知