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

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

概述1.二维码的前世今生“二维条码/二维码(2-dimensionalbarcode)是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的;在代码编制上巧妙地利用构成计算机内部逻辑基础的“

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() {@OverrIDepublic 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 algorithmfor (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,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,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() {@OverrIDepublic 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,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);}}}}@OverrIDepublic 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,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.@OverrIDepublic 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的地方:

@OverrIDepublic 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 height) {long start = System.currentTimeMillis();Result rawResult = null;//modify herebyte[] 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 #11wIDth = height;height = tmp;PlanarYUVluminanceSource source = CameraManager.get().buildluminanceSource(rotatedData,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,height);
BinaryBitmap bitmap = new BinaryBitmap(new HybrIDBinarizer(source));

总结

以上是内存溢出为你收集整理的Android平台生成二维码并实现扫描 & 识别功能全部内容,希望文章能够帮你解决Android平台生成二维码并实现扫描 & 识别功能所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1149164.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存