码迷,mamicode.com
首页 > 移动开发 > 详细

Android的二维码功能实现以及长按识别二维码

时间:2016-03-26 22:19:54      阅读:756      评论:0      收藏:0      [点我收藏+]

标签:

一、初步集成Zxing项目

            二维码的识别可是在生活中随处可见的,现在基本上所有APP都有二维码的相关操作,如果识别二维码从头开始开发做起来还是相当复杂和麻烦的,从零开始开发肯定不现实,最好的做法就是借助现有的开源项目,Github上名气最大的就是Zxing了,提供了多个平台的二维码扫码解决方案,开源项目地址是https://github.com/zxing/zxing我们今天集成Zxing到我们自己的项目中去,并实现一些二维码生成、扫描、长按识别二维码等相关操作:
       
     1.下载Zxing项目所依赖的jar包:
         下载地址是http://repo1.maven.org/maven2/com/google/zxing/core/3.2.1/选择core-3.2.1.jar下载即可,目前是最新的,原来存在将jar包导入项目无法正常运行,只有导入源码,现在是不存在这个问题的,在开源项目的下方也有下载地址,可以随时下载最新的jar包,还要下载一个jar包是android-core-3.2.1.jar,或者将这个jar包里面的只有一个类复制到工程里面也ok


     2.下载Zxing项目:
         下载地址在开源项目上下载即可,100多M,这个很简单,别跟我说你不会。

     下面我们就把zxing加入到我们的项目上去,首先把下载的Zxing项目中的源码拷贝到项目工程中去,下面我以Android Studio演示集成并实现相关功能:
     下载解压过后的样子应该是这个样子:
      
      技术分享
         点击Android下面在src看到源码复制到工程里面,在把资源文件拷贝进去,然后就是改一下AndroidMainfest其中的声明Activityde shihou ,因为都是简写,现在包名变了,改一下就好了,然后针对工程的R文件报错一个一个小心翼翼的改掉就OK了,针对有一个类报错BookmarkPickerActivity,其中大概在50行左右的时候,Browser.BOOKMARKS_URI这个报错,我把编译版本改成22就好了,基本上这样就算OK了,就像这样子:
技术分享

      然后基本运行你就可以开始扫码了。

二、获得Zxing的核心功能

              这个项目的功能多,项目很大,我们需要把最核心的功能抽取出来就好了,网上已经有很多人做出来了,大多数都是基于第一个抽取Zxing的人,但是那个是基于Zxing1.5、2.3做的,我们需要做的就是找一个旧的将这些类用最新的Zxing的代码替换掉就可以了。下面我给出一个基于ZXing3.1封装,包含了最新的jar包和代码,大家可以去下载,是医生提供的,Github中已经包含了前面所提到的所有修改(横竖屏、扭曲变形),用3.1ZXing代码进行了update,同时提供了编码、解码方法,并且将扫码界面抽取成XML(感谢开源作者),方便拓展。下载地址猛戳:

三、实现扫描和长按读取等功能

             先看效果图,录制的时候没有把鼠标录制进入,感觉不是很好,读取出来用的toast显示的,大家将就看吧
         技术分享
             实现二维码的生成,如下调用即可:
         
//生成二维码图片,第一个参数是二维码的内容,第二个参数是正方形图片的边长,单位是像素  
			Bitmap bitmap = null;
			try {
				bitmap = BitmapUtil.createQRCode(msg, 400);
			} catch (WriterException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}   
			imageView.setImageBitmap(bitmap);

       然后将生成的二维码放置到相应的位置即可。


       现在微信基本上都有长按二维码识别,这种实现我的思路就是,既然二维码扫描能够识别,那么肯定也是能够解析图片的,那么我们可以长按实现对当前屏幕截屏然后调用相关的类去解析即可:

       我们先看下截屏的代码,都有注释自己看吧:

      

	//这种方法状态栏是空白,显示不了状态栏的信息
	private void saveCurrentImage()  
	{  
		//获取当前屏幕的大小
		int width = getWindow().getDecorView().getRootView().getWidth();
		int height = getWindow().getDecorView().getRootView().getHeight();
		//生成相同大小的图片
		Bitmap temBitmap = Bitmap.createBitmap( width, height, Config.ARGB_8888 );    
		//找到当前页面的根布局
		View view =  getWindow().getDecorView().getRootView();
		//设置缓存
		view.setDrawingCacheEnabled(true);
		view.buildDrawingCache();
		//从缓存中获取当前屏幕的图片
		temBitmap = view.getDrawingCache();
		SimpleDateFormat df = new SimpleDateFormat("yyyymmddhhmmss");
		time = df.format(new Date());
		if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){
			file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/screen",time + ".png");
			if(!file.exists()){
				file.getParentFile().mkdirs();
				try {
					file.createNewFile();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			FileOutputStream fos = null;  
			try {  
				fos = new FileOutputStream(file);  
				temBitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
				fos.flush();  
				fos.close();
			} catch (FileNotFoundException e) {  
				e.printStackTrace();  
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} 
		}
	}
         

         上面将屏幕截图并以当前的时间为名字保存到手机上了,我们解析直接可以将路径传递进入解析就好了,我把相关的类传递上来,都有注释,大家看看吧:

//解析二维码图片,返回结果封装在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像素  
		//以上这种做法,虽然把bitmap限定到了我们要的大小,但是并没有节约内存,如果要节约内存,我们还需要使用inSimpleSize这个属性  
		options.inSampleSize = options.outHeight / 400;  
		if(options.inSampleSize <= 0){  
			options.inSampleSize = 1; //防止其值小于或等于0  
		}  
		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;  
	}  

                  按照zxing的解码规则,我们是需要一个BitmapLuminanceSource类的,也是唯一需要去实现的

            BitmapLuminanceSource继承自LuminanceSource这个抽象类,需要实现它的构造方法,其构造方法中需要传入宽高,这两个值指的就是图片的宽和高。getMatrix()方法会返回一个byte数组,这个数组就是图片的像素数组。getRow(int y, byte[] row)如字面的意义,就是得到图片像素数组的一行。其中的y就是需要的哪一个行的像素数组。

            以下是完整的BitmapLuminanceSource类

            

public class RGBLuminanceSource extends LuminanceSource {

	private byte bitmapPixels[];  

	protected RGBLuminanceSource(Bitmap bitmap) {  
		super(bitmap.getWidth(), bitmap.getHeight());  

		// 首先,要取得该图片的像素数组内容  
		int[] data = new int[bitmap.getWidth() * bitmap.getHeight()];  
		this.bitmapPixels = new byte[bitmap.getWidth() * bitmap.getHeight()];  
		bitmap.getPixels(data, 0, getWidth(), 0, 0, getWidth(), getHeight());  

		// 将int数组转换为byte数组,也就是取像素值中蓝色值部分作为辨析内容  
		for (int i = 0; i < data.length; i++) {  
			this.bitmapPixels[i] = (byte) data[i];  
		}  
	}  

	@Override  
	public byte[] getMatrix() {  
		// 返回我们生成好的像素数据  
		return bitmapPixels;  
	}  

	@Override  
	public byte[] getRow(int y, byte[] row) {  
		// 这里要得到指定行的像素数据  
		System.arraycopy(bitmapPixels, y * getWidth(), row, 0, getWidth());  
		return row;  
	}  
}
      

         上面获取图片像素组内容的byte[]数组是指图片的像素数组,而不是所谓的Bitmap转换成byte数组

         Bitmap对象的getPixels方法可以取得的像素数组,但它得到是int型数组。根据其api文档解释,取得的是color,也就是像素颜色值。每个像素值包含透明度,红色,绿色,蓝色。所以白色就是0xffffffff,黑色就是0xff000000。直接由int型转成byte型,实现上相当于我们这里只取其蓝色值部分。


         getPixels得到的像素数组是一维的,也就是按照图片宽度逐行取像素颜色值录入。如果想得到单行的像素数组内容,通过y*width就可以找该行的第一个像素值,拷贝后面width个就可以得到该行的像素内容。

         最后一个就是getMatrix()方法,它用来返回我们的图像转换成的像素数组。

         最后我们将长按存储的图片路径传递进去即可,但是注意解析的时候开个线程,不然要ANR,基本上实现了我们需要的大部分生成、读取、识别大部分功能。

        稍后上传源码给大家,觉得有用就点个赞吧。。。。。


Android的二维码功能实现以及长按识别二维码

标签:

原文地址:http://blog.csdn.net/qq_30806949/article/details/50959207

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!