Android平台生成二维码并实现扫描 & 识别功能

1.二维码的前世今生

“二维条码/二维码(2-dimensional bar code)是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的;在代码编制上巧妙地利用构成计算机内部逻辑基础的“0”、“1”比特流的概念,使用若干个与二进制相对应的几何形体来表示文字数值信息,通过图象输入设备或光电扫描设备自动识读以实现信息自动处理:它具有条码技术的一些共性:每种码制有其特定的字符集;每个字符占有一定的宽度;具有一定的校验功能等。同时还具有对不同行的信息自动识别功能、及处理图形旋转变化点。 [1] ”

上面是百度百科的解释。既然有二维码,那么肯定有一维码。

一维码。最为常见的就是食品 & 书本后面的条码。

条码起源与20世纪40年代,后来在1970年 UPC码发明,并开始广泛应用与食品包装。

具体的介绍可以看百度百科 一维码。

其实二维码与一维码本质上是类似的,就跟一维数组和二维数组一样。

2.二维码的java支持库

为了让java或者说android方便继承条码的功能,google就开发了一个zxing的库:

https://github.com/zxing/zxing

3.生成二维码

public class EncodeThread { public static void encode(final String url, final int width, final int height, final EncodeResult result) { if (result == null) { return; } if (TextUtils.isEmpty(url)) { result.onEncodeResult(null); return; } new Thread() { @Override public void run() { try { MultiFormatWriter writer = new MultiFormatWriter(); Hashtable<EncodeHintType, String> hints = new Hashtable<>(); hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); BitMatrix bitMatrix = writer.encode(url, BarcodeFormat.QR_CODE, width, height, hints); Bitmap bitmap = parseBitMatrix(bitMatrix); result.onEncodeResult(bitmap); return; } catch (WriterException e) { e.printStackTrace(); } result.onEncodeResult(null); } }.start(); } /** * 生成二维码内容<br> * * @param matrix * @return */ public static Bitmap parseBitMatrix(BitMatrix matrix) { final int QR_WIDTH = matrix.getWidth(); final int QR_HEIGHT = matrix.getHeight(); int[] pixels = new int[QR_WIDTH * QR_HEIGHT]; //this we using qrcode algorithm for (int y = 0; y < QR_HEIGHT; y++) { for (int x = 0; x < QR_WIDTH; x++) { if (matrix.get(x, y)) { pixels[y * QR_WIDTH + x] = 0xff000000; } else { pixels[y * QR_WIDTH + x] = 0xffffffff; } } } Bitmap bitmap = Bitmap.createBitmap(QR_WIDTH, QR_HEIGHT, Bitmap.Config.ARGB_8888); bitmap.setPixels(pixels, 0, QR_WIDTH, 0, 0, QR_WIDTH, QR_HEIGHT); return bitmap; } public interface EncodeResult { void onEncodeResult(Bitmap bitmap); } }

zxing 支持很多条码格式:我们这里使用QR_CODE码。也就是我们常见的微信里面的二维码。

我们先来分析下这段代码:

MultiFormatWriter writer = new MultiFormatWriter();

这个是一个工具类,把所有支持的几个write写在里面了。

public BitMatrix encode(String contents, BarcodeFormat format, int width, int height, Map<EncodeHintType,?> hints) throws WriterException { Writer writer; switch (format) { case EAN_8: writer = new EAN8Writer(); break; case UPC_E: writer = new UPCEWriter(); break; case EAN_13: writer = new EAN13Writer(); break; case UPC_A: writer = new UPCAWriter(); break; case QR_CODE: writer = new QRCodeWriter(); break; case CODE_39: writer = new Code39Writer(); break; case CODE_93: writer = new Code93Writer(); break; case CODE_128: writer = new Code128Writer(); break; case ITF: writer = new ITFWriter(); break; case PDF_417: writer = new PDF417Writer(); break; case CODABAR: writer = new CodaBarWriter(); break; case DATA_MATRIX: writer = new DataMatrixWriter(); break; case AZTEC: writer = new AztecWriter(); break; default: throw new IllegalArgumentException("No encoder available for format " + format); } return writer.encode(contents, format, width, height, hints); }

这是官方最新支持的格式,具体看引入的jar里面支持的格式。

对与bitmatrix的结果,通过摸个算法,设置每个点白色,或者黑色。

最后创建一张二维码的图片。

4.识别二维码

如何从一张图片上面,识别二维码呢:

public class ReDecodeThread { public static void encode(final Bitmap bitmap, final ReDecodeThreadResult listener) { if (listener == null) { return; } if (bitmap == null) { listener.onReDecodeResult(null); return; } new Thread() { @Override public void run() { try { MultiFormatReader multiFormatReader = new MultiFormatReader(); BitmapLuminanceSource source = new BitmapLuminanceSource(bitmap); BinaryBitmap bitmap1 = new BinaryBitmap(new HybridBinarizer(source)); Result result1 = multiFormatReader.decode(bitmap1); listener.onReDecodeResult(result1.getText()); return; } catch (NotFoundException e) { e.printStackTrace(); } listener.onReDecodeResult(null); } }.start(); } public interface ReDecodeThreadResult { void onReDecodeResult(String url); } }

过程也是很简单,使用MultiFormatReader来分析图片,这里不需要缺人图片的条码格式。

如果分析下源码,就是依次使用每种格式的reader来分析,直到找到合适的为止。

当然回了能够把Bitmap转化成Bitmatrix,然后在分析。

public final class BitmapLuminanceSource extends LuminanceSource{ private final byte[] luminances; public BitmapLuminanceSource(String path) throws FileNotFoundException { this(loadBitmap(path)); } public BitmapLuminanceSource(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); // In order to measure pure decoding speed, we convert the entire image // to a greyscale array // up front, which is the same as the Y channel of the // YUVLuminanceSource in the real app. 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) { // Image is already greyscale, so pick any channel. luminances[offset + x] = (byte) r; } else { // Calculate luminance cheaply, favoring green. luminances[offset + x] = (byte) ((r + g + g + b) >> 2); } } } } @Override public byte[] getRow(int y, byte[] row) { if (y < 0 || y >= getHeight()) { throw new IllegalArgumentException("Requested row is outside the image: " + y); } int width = getWidth(); if (row == null || row.length < width) { row = new byte[width]; } System.arraycopy(luminances, y * width, row, 0, width); return row; } // Since this class does not support cropping, the underlying byte array // already contains // exactly what the caller is asking for, so give it to them without a copy. @Override public byte[] getMatrix() { return luminances; } 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; } }

5.扫描二维码

扫描二维码,其实比上面只多了一步,就是把camera获取的东西直接转换,然后进行识别。

public void requestPreviewFrame(Handler handler, int message) { if (camera != null && previewing) { previewCallback.setHandler(handler, message); if (useOneShotPreviewCallback) { camera.setOneShotPreviewCallback(previewCallback); } else { camera.setPreviewCallback(previewCallback); } } }

首先把camera预览的数据放入previewCallback中。

final class PreviewCallback implements Camera.PreviewCallback public void onPreviewFrame(byte[] data, Camera camera) { Point cameraResolution = configManager.getCameraResolution(); if (!useOneShotPreviewCallback) { camera.setPreviewCallback(null); } if (previewHandler != null) { Message message = previewHandler.obtainMessage(previewMessage, cameraResolution.x, cameraResolution.y, data); message.sendToTarget(); previewHandler = null; } else { Log.d(TAG, "Got preview callback, but no handler for it"); } }

可以看到,预览的数据data,回传递过来,然后handler的方式传递出去。

接收data的地方:

@Override public void handleMessage(Message message) { switch (message.what) { case R.id.decode: //Log.d(TAG, "Got decode message"); decode((byte[]) message.obj, message.arg1, message.arg2); break; case R.id.quit: Looper.myLooper().quit(); break; } }

然后是decode data

private void decode(byte[] data, int width, int height) { long start = System.currentTimeMillis(); Result rawResult = null; //modify here byte[] rotatedData = new byte[data.length]; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) rotatedData[x * height + height - y - 1] = data[x + y * width]; } int tmp = width; // Here we are swapping, that's the difference to #11 width = height; height = tmp; PlanarYUVLuminanceSource source = CameraManager.get().buildLuminanceSource(rotatedData, width, height); BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); try { rawResult = multiFormatReader.decodeWithState(bitmap); } catch (ReaderException re) { // continue } finally { multiFormatReader.reset(); } if (rawResult != null) { long end = System.currentTimeMillis(); Log.d(TAG, "Found barcode (" + (end - start) + " ms):\n" + rawResult.toString()); Message message = Message.obtain(activity.getHandler(), R.id.decode_succeeded, rawResult); Bundle bundle = new Bundle(); bundle.putParcelable(DecodeThread.BARCODE_BITMAP, source.renderCroppedGreyscaleBitmap()); message.setData(bundle); //Log.d(TAG, "Sending decode succeeded message..."); message.sendToTarget(); } else { Message message = Message.obtain(activity.getHandler(), R.id.decode_failed); message.sendToTarget(); } }

当把camera上的图片转换成BinaryBitmap以后,剩下的事情,就更直接从图片识别是一样的。

PlanarYUVLuminanceSource source = CameraManager.get().buildLuminanceSource(rotatedData, width, height);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));

时间: 2024-10-23 15:27:48

Android平台生成二维码并实现扫描 & 识别功能的相关文章

Android平台生成二维码并实现扫描 &amp; 识别功能_Android

1.二维码的前世今生 "二维条码/二维码(2-dimensional bar code)是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的:在代码编制上巧妙地利用构成计算机内部逻辑基础的"0"."1"比特流的概念,使用若干个与二进制相对应的几何形体来表示文字数值信息,通过图象输入设备或光电扫描设备自动识读以实现信息自动处理:它具有条码技术的一些共性:每种码制有其特定的字符集:每个字符占有一定的宽度:具有一定的校验功能

Android Zxing生成二维码经典案例分享_Android

本文实例为大家解析了Zxing生成二维码的经典案例,供大家参考,具体内容如下 1.首先呢,先编译 compile 'com.google.zxing:core:3.2.1' 2.实战 public class QRCode { private static int IMAGE_HALFWIDTH = 50;//宽度值,影响中间图片大小 /** * 生成二维码,默认大小为500*500 * * @return bitmap */ public static Bitmap createQRCode(

Android Zxing生成二维码经典案例分享

本文实例为大家解析了Zxing生成二维码的经典案例,供大家参考,具体内容如下 1.首先呢,先编译 compile 'com.google.zxing:core:3.2.1' 2.实战 public class QRCode { private static int IMAGE_HALFWIDTH = 50;//宽度值,影响中间图片大小 /** * 生成二维码,默认大小为500*500 * * @return bitmap */ public static Bitmap createQRCode(

Android 点击生成二维码功能实现代码

先看效果: 输入内容,点击生成二维码: 点击logo图案: 代码: QRCodeUtil: package com.example.administrator.zxing; import android.graphics.Bitmap; import android.graphics.Canvas; import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zx

iOS和Android用同一个二维码实现跳转下载链接的方法_javascript技巧

前言 最近一个项目需要iOS和安卓使用一个二维码,让扫描的机器自己识别操作系统实现跳转到相应的下载链接.比如iPhone用微信进行扫描就让他跳转appStore的下载页面,安卓机器使用微信扫描就直接跳浏览器下载.但是这二维码还有一个需求就是,用户已经下载了这个app,当用户打开app进入到注册页面时,再次扫描这个二维码时,自动填写邀请码进行注册.那么该如何实现,细节就不说了,直接上代码. 使用js实现,其实代码非常简单. 使用时直接拷贝代码,改掉相应的链接就好. PS:该链接在微信环境打开时还是

zximg怎么用-zxing3.0生成二维码怎么用

问题描述 zxing3.0生成二维码怎么用 2.2版本的代码放到3.0之后就不能用了,求解释,给我发个代码也行,谢谢 解决方案 http://ask.csdn.net/questions/163257 解决方案二: ZXing二维码生成ZXing 为Android应用生成二维码关于使用Zxing生成二维码的一些调整

Android平台利用ZXING生成二维码图片

zxing是google的一个开源二维码项目,目前基本上和二维码打交道的东西,都会用到它. 最近项目中用到了android手机需要根据提供的字符串生成二维码图片,之前用zxing做过二维码解码,编码还没做过,看了一些demo都是用到了zxing的j2se包的内容,这个在android或者其他平台上显然无法实现,所以我们要利用zxing生成二维矩阵,然后根据android平台的提供的api来生成图片. /** * 用字符串生成二维码 * @param str * @author zhouzhe@l

android 使用开源库zxing生成二维码,扫描二维码【转】

转自:http://blog.csdn.net/qq_16064871/article/details/52422723 zxing是一个开放源码的,用Java实现的多种格式的1D/2D条码图像处理库,它包含了联系到其他语言的接口.可以实现使用手机的内置的摄像头完成条形码和二维码的扫描与解码.可以实现条形码和二维码的编码与解码. github官网源码地址:https://github.com/zxing/zxing 开源库api文档:https://zxing.github.io/zxing/a

微信公众平台怎么生成二维码名片?

  接触过微信公众平台的人都知道,人们可以根据微信公众平台的唯一二维码进行扫描关注.那么,这个微信公众平台二维码怎么生成呢?去哪里找呢?下面来告诉大家. 1.首先,需要登录自己的微信公众平台电脑端后台: 2.然后,有两种方法进入微信公众号设置 里. 1)点击右上角的微信公众号头像 或名称: 2)看到左侧的那些栏目 ,下面有一个"公众号设置 "的选项,点击进入: 3.然后在公众号设置页面,往下拉滚动条,一直到最下面: 4.然后就可以在最下面看到此公众号的二维码 了,直接点击此二维码图片或