二维码之zxing二维码解析图片资源



zxing针对不同开发平台,都给出了解析二维码的例子,我这里只聊聊关于android系统的解析。

对于android手机来说,二维码图像获取方式有拍照扫描,以及读取本地图片资源。无论是哪种方式,解析过程的核心内容基本是一样的。关于手机拍照扫描这块,由于要涉及到很多问题要讲,所以我打算把这块放在下篇文章再细致讲解,这次只讲如何对图片进行解析。

首先,和生成二维码一样,我们要告诉系统解析二维码的设置参数。这里我选择了支持主流的三类方式,其中一种为一维码(条形码)。设置解析的字符位UTF8。如果不设置字符解析方式,它会自己去识别内容,然后自己判断该用哪种方式。

看一下设置参数的代码:

  1. MultiFormatReader multiFormatReader = new MultiFormatReader();  
  2.   
  3. // 解码的参数  
  4. Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(  
  5.         2);  
  6. // 可以解析的编码类型  
  7. Vector<BarcodeFormat> decodeFormats = new Vector<BarcodeFormat>();  
  8. if (decodeFormats == null || decodeFormats.isEmpty()) {  
  9.     decodeFormats = new Vector<BarcodeFormat>();  
  10.   
  11.     // 这里设置可扫描的类型,我这里选择了都支持  
  12.     decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS);  
  13.     decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS);  
  14.     decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS);  
  15. }  
  16. hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats);  
  17.   
  18. // 设置继续的字符编码格式为UTF8  
  19. // hints.put(DecodeHintType.CHARACTER_SET, "UTF8");  
  20.   
  21. // 设置解析配置参数  
  22. multiFormatReader.setHints(hints);  
		MultiFormatReader multiFormatReader = new MultiFormatReader();

		// 解码的参数
		Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(
				2);
		// 可以解析的编码类型
		Vector<BarcodeFormat> decodeFormats = new Vector<BarcodeFormat>();
		if (decodeFormats == null || decodeFormats.isEmpty()) {
			decodeFormats = new Vector<BarcodeFormat>();

			// 这里设置可扫描的类型,我这里选择了都支持
			decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS);
			decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS);
			decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS);
		}
		hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats);

		// 设置继续的字符编码格式为UTF8
		// hints.put(DecodeHintType.CHARACTER_SET, "UTF8");

		// 设置解析配置参数
		multiFormatReader.setHints(hints);


补一句:zxing源码中对UTF8的定义字符串内容不是UTF-8,而是UTF8。
private static final String UTF8 = "UTF8";

 

再来就是解析部分:

  1. // 开始对图像资源解码  
  2. Result rawResult = null;  
  3. try {  
  4.   
  5.     rawResult = multiFormatReader  
  6.             .decodeWithState(new BinaryBitmap(new HybridBinarizer(  
  7.                     new BitmapLuminanceSource(BitmapFactory  
  8.                             .decodeResource(getResources(),  
  9.                                     R.drawable.weibo)))));  
  10. catch (NotFoundException e) {  
  11.     e.printStackTrace();  
  12. }  
		// 开始对图像资源解码
		Result rawResult = null;
		try {

			rawResult = multiFormatReader
					.decodeWithState(new BinaryBitmap(new HybridBinarizer(
							new BitmapLuminanceSource(BitmapFactory
									.decodeResource(getResources(),
											R.drawable.weibo)))));
		} catch (NotFoundException e) {
			e.printStackTrace();
		}


按照zxing的解码规则,需要传入一个LuminanceSource类的对象,最后就会得到解析结果result对象,也就是解码后的信息类。这里唯一需要自己实现的就是BitmapLuminanceSource类。

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

先看构造方法:

  1. protected BitmapLuminanceSource(Bitmap bitmap) {  
  2.     super(bitmap.getWidth(), bitmap.getHeight());  
  3.   
  4.     // 首先,要取得该图片的像素数组内容  
  5.     int[] data = new int[bitmap.getWidth() * bitmap.getHeight()];  
  6.     this.bitmapPixels = new byte[bitmap.getWidth() * bitmap.getHeight()];  
  7.     bitmap.getPixels(data, 0, getWidth(), 00, getWidth(), getHeight());  
  8.   
  9.     // 将int数组转换为byte数组  
  10.     for (int i = 0; i < data.length; i++) {  
  11.         this.bitmapPixels[i] = (byte) data[i];  
  12.     }  
  13. }  
	protected BitmapLuminanceSource(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];
		}
	}

注意:这里的byte数组是指图片的像素数组,而不是所谓Bitmap转换成byte数组,有人出现解析的错误,大多是对这个参数用途没理解造成的。

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

 

再来就是getRow方法:

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


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

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

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


以下是完整的BitmapLuminanceSource类:

  1.   public class BitmapLuminanceSource extends LuminanceSource {  
  2.   
  3.     private byte bitmapPixels[];  
  4.   
  5.     protected BitmapLuminanceSource(Bitmap bitmap) {  
  6.         super(bitmap.getWidth(), bitmap.getHeight());  
  7.   
  8.         // 首先,要取得该图片的像素数组内容  
  9.         int[] data = new int[bitmap.getWidth() * bitmap.getHeight()];  
  10.         this.bitmapPixels = new byte[bitmap.getWidth() * bitmap.getHeight()];  
  11.         bitmap.getPixels(data, 0, getWidth(), 00, getWidth(), getHeight());  
  12.   
  13.         // 将int数组转换为byte数组,也就是取像素值中蓝色值部分作为辨析内容  
  14.         for (int i = 0; i < data.length; i++) {  
  15.             this.bitmapPixels[i] = (byte) data[i];  
  16.         }  
  17.     }  
  18.   
  19.     @Override  
  20.     public byte[] getMatrix() {  
  21.         // 返回我们生成好的像素数据  
  22.         return bitmapPixels;  
  23.     }  
  24.   
  25.     @Override  
  26.     public byte[] getRow(int y, byte[] row) {  
  27.         // 这里要得到指定行的像素数据  
  28.         System.arraycopy(bitmapPixels, y * getWidth(), row, 0, getWidth());  
  29.         return row;  
  30.     }  
  31. }  
  public class BitmapLuminanceSource extends LuminanceSource {

	private byte bitmapPixels[];

	protected BitmapLuminanceSource(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;
	}
}


好了,最后就得到了我们想要的Result对象。
这个对象中包含了很多内容,包括内容,编码方式,解析时间等。
我们想要的内容就放在rawResult.getText()中,你还可以得到它的编码方式rawResult.getBarcodeFormat()。

 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值