用Camera的预览和zXing来写一个二维码扫描功能
来源:互联网 发布:单片机制作电子时钟 编辑:程序博客网 时间:2024/06/07 07:01
首先我这里不会再介绍Camera的基本属性了解介绍了,也不会讲预览的基本设置。会直奔主题将怎么写二维码扫描的界面的自定义控件和扫描过程实现以及里面。至于Camera的基本介绍请看我之前的博客:Camera基本介绍,用Camera写一个自己的基本预览界面。这两篇博客是这个二维码扫描的基础篇。
(1)声明自己要解析那些类型的,必须解析二维码、解析条形码。
(2)开启一个线程去读取预览界面的指定区域的数据源(byte[])
(3)利用zXing的方法去先判断获取到的数据源里面的点是否是有效的,再在有效的基础上结合(1)声明的格式去解析这些有用的点,直到解析成功、失败、主动或被动停止为止。
(4)扫描过程从始至终都会有自定义控件和动画跟随着,所以这个(4)是贯穿整个过程并且受到(3)的控制。
(5)回调(3)执行结果来控制(4);
下面我对上面的四点进行分别解析:
(1)声明解析类型:
import android.content.Intent;import android.net.Uri;import com.google.zxing.BarcodeFormat;import java.util.Arrays;import java.util.List;import java.util.Vector;import java.util.regex.Pattern;public class DecodeFormatManager { private static final Pattern COMMA_PATTERN = Pattern.compile(","); static final Vector<BarcodeFormat> PRODUCT_FORMATS; static final Vector<BarcodeFormat> ONE_D_FORMATS; static final Vector<BarcodeFormat> QR_CODE_FORMATS; static final Vector<BarcodeFormat> DATA_MATRIX_FORMATS; static { PRODUCT_FORMATS = new Vector<>(5); PRODUCT_FORMATS.add(BarcodeFormat.UPC_A); PRODUCT_FORMATS.add(BarcodeFormat.UPC_E); PRODUCT_FORMATS.add(BarcodeFormat.EAN_13); PRODUCT_FORMATS.add(BarcodeFormat.EAN_8); ONE_D_FORMATS = new Vector<>(PRODUCT_FORMATS.size() + 4); ONE_D_FORMATS.addAll(PRODUCT_FORMATS); ONE_D_FORMATS.add(BarcodeFormat.CODE_39); ONE_D_FORMATS.add(BarcodeFormat.CODE_93); ONE_D_FORMATS.add(BarcodeFormat.CODE_128); ONE_D_FORMATS.add(BarcodeFormat.ITF); QR_CODE_FORMATS = new Vector<>(1); QR_CODE_FORMATS.add(BarcodeFormat.QR_CODE); DATA_MATRIX_FORMATS = new Vector<>(1); DATA_MATRIX_FORMATS.add(BarcodeFormat.DATA_MATRIX); } private DecodeFormatManager() { } private static final class Holder { private static final DecodeFormatManager DECODE_FORMAT_MANAGER = new DecodeFormatManager(); } public static DecodeFormatManager getInstance() { return Holder.DECODE_FORMAT_MANAGER; } static Vector<BarcodeFormat> parseDecodeFormats(Intent intent) { List<String> scanFormats = null; String scanFormatsString = intent.getStringExtra(Intents.Scan.SCAN_FORMATS); if (scanFormatsString != null) { scanFormats = Arrays.asList(COMMA_PATTERN.split(scanFormatsString)); } return parseDecodeFormats(scanFormats, intent.getStringExtra(Intents.Scan.MODE)); } static Vector<BarcodeFormat> parseDecodeFormats(Uri inputUri) { List<String> formats = inputUri.getQueryParameters(Intents.Scan.SCAN_FORMATS); if (formats != null && formats.size() == 1 && formats.get(0) != null) { formats = Arrays.asList(COMMA_PATTERN.split(formats.get(0))); } return parseDecodeFormats(formats, inputUri.getQueryParameter(Intents.Scan.MODE)); } private static Vector<BarcodeFormat> parseDecodeFormats(Iterable<String> scanFormats, String decodeMode) { if (scanFormats != null) { Vector<BarcodeFormat> formats = new Vector<BarcodeFormat>(); try { for (String format : scanFormats) { formats.add(BarcodeFormat.valueOf(format)); } return formats; } catch (IllegalArgumentException iae) { // ignore it then } } if (decodeMode != null) { if (Intents.Scan.PRODUCT_MODE.equals(decodeMode)) { return PRODUCT_FORMATS; } if (Intents.Scan.QR_CODE_MODE.equals(decodeMode)) { return QR_CODE_FORMATS; } if (Intents.Scan.DATA_MATRIX_MODE.equals(decodeMode)) { return DATA_MATRIX_FORMATS; } if (Intents.Scan.ONE_D_MODE.equals(decodeMode)) { return ONE_D_FORMATS; } } return null; }}(2和3)开启线程去读取预览界面的指定区域的数据源,然后在线程里面使用handler来不断的读取和解析数据:
import android.app.Activity;import android.os.Handler;import android.os.Looper;import com.google.zxing.BarcodeFormat;import com.google.zxing.DecodeHintType;import com.google.zxing.ResultPointCallback;import java.util.Hashtable;import java.util.Vector;import java.util.concurrent.CountDownLatch;public class DecodeThread extends Thread { private Activity activity; private final CountDownLatch handlerInitLatch; private DecodeHandler handler; private final Hashtable<DecodeHintType, Object> hints; public static final String BARCODE_BITMAP = "barcode_bitmap"; public DecodeThread(Activity activity, Vector<BarcodeFormat> decodeFormats, String characterSet, ResultPointCallback resultPointCallback) { this.activity = activity; handlerInitLatch = new CountDownLatch(1); //Decode Hint Type 解码提示类型 hints = new Hashtable<>(3);//哈希表集合 if (decodeFormats == null || decodeFormats.isEmpty()) { decodeFormats = new Vector<>(); decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS); decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS); decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS); } hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats); if (characterSet != null) { hints.put(DecodeHintType.CHARACTER_SET, characterSet); } hints.put(DecodeHintType.NEED_RESULT_POINT_CALLBACK, resultPointCallback); } Handler getHandler() { try { handlerInitLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } return handler; } @Override public void run() { super.run(); Looper.prepare(); handler = new DecodeHandler(activity, hints); handlerInitLatch.countDown(); Looper.loop(); }}
import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Looper;import android.os.Message;import com.google.zxing.BinaryBitmap;import com.google.zxing.DecodeHintType;import com.google.zxing.MultiFormatReader;import com.google.zxing.NotFoundException;import com.google.zxing.Result;import com.google.zxing.common.HybridBinarizer;import java.util.Hashtable;import shen.da.ye.myscandemo.R;import shen.da.ye.myscandemo.ScanActivity;import shen.da.ye.myscandemo.camera.CameraManager;import shen.da.ye.myscandemo.camera.PlanarYUVLuminanceSource;public class DecodeHandler extends Handler { private static final String TAG = "cy==DecodeHandler"; private final MultiFormatReader MULITFORMATREADER; private Activity activity; public DecodeHandler(Activity activity, Hashtable<DecodeHintType, Object> hints) { MULITFORMATREADER = new MultiFormatReader(); MULITFORMATREADER.setHints(hints); this.activity = activity; } @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case R.id.decode: decode(((byte[]) msg.obj), msg.arg1, msg.arg2); break; case R.id.quit: Looper.myLooper().quit(); default: break; } } /** * 解码取景器矩形中的数据,以及花费多长时间。 为了效率,将相同的读取对象从一个解码重用到下一个解码。 * * @param data The YUV preview frame. * @param width The width of the preview frame. * @param height The height of the preview frame. */ private void decode(byte[] data, int width, int height) { //解析从预览界面的矩形中的数据 long start = System.currentTimeMillis(); Result rawResult = null; byte[] rotateData = new byte[data.length]; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { rotateData[x * height + height - y - 1] = data[x + y * width]; } } int tmp = width; width = height; height = tmp; //二维码扫描核心处理代码是在这里调用zXing PlanarYUVLuminanceSource planarYUVLuminanceSource = CameraManager.getInstance().buildLuminanceSource(rotateData, width, height); BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(planarYUVLuminanceSource)); try { rawResult = MULITFORMATREADER.decodeWithState(bitmap); } catch (NotFoundException e) { e.printStackTrace(); } finally { MULITFORMATREADER.reset(); } if (rawResult != null) { long end = System.currentTimeMillis(); Message message = Message.obtain(((ScanActivity) activity).getHandler(), R.id.decode_succeeded, rawResult); Bundle bundle = new Bundle(); bundle.putParcelable(DecodeThread.BARCODE_BITMAP, planarYUVLuminanceSource.renderCroppedGreyScaleBitmap()); message.setData(bundle); message.sendToTarget(); } else { Message message = Message.obtain(((ScanActivity) activity).getHandler(), R.id.decode_failed); message.sendToTarget(); } }}
(5)再用一个hander来解决线程里面读取数据的信息回调:
import android.app.Activity;import android.content.Intent;import android.graphics.Bitmap;import android.net.Uri;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.util.Log;import com.google.zxing.BarcodeFormat;import com.google.zxing.Result;import java.util.Vector;import shen.da.ye.myscandemo.R;import shen.da.ye.myscandemo.ScanActivity;import shen.da.ye.myscandemo.camera.CameraManager;public class CaptureActivityHandler extends Handler { private static final String TAG = "cy====CaptureHandler"; private Activity activity; private State mState; private final DecodeThread decodeThread; private enum State { PREVIEW, SUCCESS, DONE } /*Vector:向量,Barcode Format:条码格式*/ public CaptureActivityHandler(Activity activity, Vector<BarcodeFormat> barcodeFormats, String characterSet) { this.activity = activity; decodeThread = new DecodeThread(activity, barcodeFormats, characterSet, new ViewfinderResultPointCallback(((ScanActivity) activity).getViewfinderView())); decodeThread.start(); mState = State.SUCCESS; //(1)开始预览 CameraManager.getInstance().startPreview(); //(2)开始解码 restartDecode(); } private void restartDecode() { if (mState == State.SUCCESS) { mState = State.PREVIEW; CameraManager.getInstance().requestPreviewFrame(decodeThread.getHandler(), R.id.decode); CameraManager.getInstance().requestAutoFocus(this, R.id.auto_focus); ((ScanActivity) activity).drawViewfinder(); } } @Override public void handleMessage(Message msg) { switch (msg.what) { case R.id.auto_focus: //接收到自动定焦msg if (mState == State.PREVIEW) { CameraManager.getInstance().requestAutoFocus(this, R.id.auto_focus); Log.i(TAG, "自动定焦"); } break; case R.id.restart_preview: //接收到重新启动预览的msg,是在扫描走了onPause之后再走onResume的时候调用这个方法 restartDecode();//TODO 看一下这个需不需要再重新开始预览,加一个跳转界面测试一下 break; case R.id.decode_succeeded: //接收到解码成功的msg mState = State.SUCCESS; Bundle bundle = msg.getData(); Bitmap barcode = bundle == null ? null : (Bitmap) bundle.getParcelable(DecodeThread.BARCODE_BITMAP); ((ScanActivity) activity).handleDecode((Result) msg.obj, barcode); Log.i(TAG, "解析扫描到捕捉的点成功"); break; case R.id.decode_failed: //接收到扫描失败的msg,这个扫描失败是捕捉到的东西不是一个正常的条形码和二维码,那么继续捕捉。还有一个扫描时失败是捕捉到的点是二维码,但是从里面解析到的数据失败 mState = State.PREVIEW; CameraManager.getInstance().requestPreviewFrame(decodeThread.getHandler(), R.id.decode); Log.i(TAG, "捕捉的点经过解析是无效的,重新再捕捉"); break; case R.id.return_scan_result: //接收到 activity.setResult(Activity.RESULT_OK, ((Intent) msg.obj)); activity.finish(); break; case R.id.launch_product_query: //接收到 String url = (String) msg.obj; Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); activity.startActivity(intent); break; default: break; } } //onPause的时候停止扫描 public void quitSynchronously() { mState = State.DONE; CameraManager.getInstance().stopPreview(); Message quit = Message.obtain(decodeThread.getHandler(), R.id.quit); quit.sendToTarget(); try { decodeThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } //移除到正在发送的信息,保证现在没有任何排队的信息 removeMessages(R.id.decode_succeeded); removeMessages(R.id.decode_failed); }}源代码
阅读全文
0 0
- 用Camera的预览和zXing来写一个二维码扫描功能
- zxing二维码扫描预览变形的解决方案
- Android纯的二维码扫描界面和功能-zxing
- zxing二维码扫描功能
- 使用zxing实现二维码的扫描功能
- zxing扫描二维码遇到的一个问题
- # Zxing二维码扫描图片预览变形的问题解决
- Zxing二维码的扫描
- Android二维码的扫描和生成(ZXing)
- ZXing 生成二维码 (这里只写了生成二维码,没有写扫描二维码功能)
- 基于Zxing的二维码生成和二维码扫描
- 基于Zxing的二维码生成和二维码扫描
- 基于Zxing的二维码生成和二维码扫描
- 自己写的关于zxing二维码扫描的例子
- 使用Google ZXing实现二维码的扫描和生成相关功能体系
- 用google zxing生成二维码和扫描二维码
- 基于zxing的二维码扫描
- 使用Zxing来实现二维码扫描
- jmeter的用法
- 笔记:linux下安装nginx
- Android 设计模式
- Zookeeper注册中心的搭建
- 机器学习中的必修数学(九)
- 用Camera的预览和zXing来写一个二维码扫描功能
- Practise 2
- 数据库中dataTime,Time以及timeStamp字段的差别
- 二叉搜索树的操作集
- (原)win8下编译GLUT
- 数据库索引
- 实验报告_ASE_lab3
- C++——【USACO 3.3.3】——Camelot
- python直观的http与https的区别