zxing二维码扫描的流程简析(Android版)
目前市面上二维码的扫描似乎用开源google的zxing比较多,接下去以2.2版本做一个简析吧,勿喷。。。
下载下来后定位两个文件夹,core和android,core是一些核心的库,android是针对android的一些代码。

我们先看核心库,在package com.google.zxing中的一些生成二维码的类关系

接口Writer里面有两个encode的重载函数,不同的格式的二维码有各自的类实现了Writer接口,MultiformatWriter类比较特殊,根据代码的注释可见其其实是个工厂类,根据BarcodeFormat实例化不同的Writer,然后最终调用各自的Encode.encode()方法
public final class MultiFormatWriter implements Writer {
@Override
public BitMatrix encode(String contents,
BarcodeFormat format,
int width,
int height) throws WriterException {
return encode(contents, format, width, height, null);
}
@Override
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 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_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);
}
}
然后看解析二维码的类结构

关键就是这个MultiformatReader,里面聚合了多个reader,并且根据客户端设置的DecodeHintType值,确定添加reader以及添加reader的顺序,最后调用reader.decode方法
public final class MultiFormatReader implements Reader {
private Map<DecodeHintType,?> hints;
private Reader[] readers;
@Override
public Result decode(BinaryBitmap image) throws NotFoundException {
setHints(null);
return decodeInternal(image);
}
@Override
public Result decode(BinaryBitmap image, Map<DecodeHintType,?> hints) throws NotFoundException {
setHints(hints);
return decodeInternal(image);
}
public Result decodeWithState(BinaryBitmap image) throws NotFoundException {
// Make sure to set up the default state so we don't crash
if (readers == null) {
setHints(null);
}
return decodeInternal(image);
}
public void setHints(Map<DecodeHintType,?> hints) {//根据设置的hint来设置reader
this.hints = hints;
boolean tryHarder = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER);
@SuppressWarnings("unchecked")
Collection<BarcodeFormat> formats =
hints == null ? null : (Collection<BarcodeFormat>) hints.get(DecodeHintType.POSSIBLE_FORMATS);
Collection<Reader> readers = new ArrayList<Reader>();
if (formats != null) {
boolean addOneDReader =
formats.contains(BarcodeFormat.UPC_A) ||
formats.contains(BarcodeFormat.UPC_E) ||
formats.contains(BarcodeFormat.EAN_13) ||
formats.contains(BarcodeFormat.EAN_8) ||
formats.contains(BarcodeFormat.CODABAR) ||
formats.contains(BarcodeFormat.CODE_39) ||
formats.contains(BarcodeFormat.CODE_93) ||
formats.contains(BarcodeFormat.CODE_128) ||
formats.contains(BarcodeFormat.ITF) ||
formats.contains(BarcodeFormat.RSS_14) ||
formats.contains(BarcodeFormat.RSS_EXPANDED);
// Put 1D readers upfront in "normal" mode
if (addOneDReader && !tryHarder) {
readers.add(new MultiFormatOneDReader(hints));
}
if (formats.contains(BarcodeFormat.QR_CODE)) {
readers.add(new QRCodeReader());
}
if (formats.contains(BarcodeFormat.DATA_MATRIX)) {
readers.add(new DataMatrixReader());
}
if (formats.contains(BarcodeFormat.AZTEC)) {
readers.add(new AztecReader());
}
if (formats.contains(BarcodeFormat.PDF_417)) {
readers.add(new PDF417Reader());
}
if (formats.contains(BarcodeFormat.MAXICODE)) {
readers.add(new MaxiCodeReader());
}
// At end in "try harder" mode
if (addOneDReader && tryHarder) {
readers.add(new MultiFormatOneDReader(hints));
}
}
if (readers.isEmpty()) {
if (!tryHarder) {
readers.add(new MultiFormatOneDReader(hints));
}
readers.add(new QRCodeReader());
readers.add(new DataMatrixReader());
readers.add(new AztecReader());
readers.add(new PDF417Reader());
readers.add(new MaxiCodeReader());
if (tryHarder) {
readers.add(new MultiFormatOneDReader(hints));
}
}
this.readers = readers.toArray(new Reader[readers.size()]);
}
@Override
public void reset() {
if (readers != null) {
for (Reader reader : readers) {
reader.reset();
}
}
}
private Result decodeInternal(BinaryBitmap image) throws NotFoundException {//最终都调用这个方法
if (readers != null) {
for (Reader reader : readers) {
try {
return reader.decode(image, hints);
} catch (ReaderException re) {
// continue
}
}
}
throw NotFoundException.getNotFoundInstance();
}
}
DecodeHintType的语法比较有意思,还在理解中
public enum DecodeHintType {
/**
* Unspecified, application-specific hint. Maps to an unspecified {@link Object}.
*/
OTHER(Object.class),
/**
* Image is a pure monochrome image of a barcode. Doesn't matter what it maps to;
* use {@link Boolean#TRUE}.
*/
PURE_BARCODE(Void.class),
/**
* Image is known to be of one of a few possible formats.
* Maps to a {@link List} of {@link BarcodeFormat}s.
*/
POSSIBLE_FORMATS(List.class),
/**
* Spend more time to try to find a barcode; optimize for accuracy, not speed.
* Doesn't matter what it maps to; use {@link Boolean#TRUE}.
*/
TRY_HARDER(Void.class),
/**
* Specifies what character encoding to use when decoding, where applicable (type String)
*/
CHARACTER_SET(String.class),
/**
* Allowed lengths of encoded data -- reject anything else. Maps to an {@code int[]}.
*/
ALLOWED_LENGTHS(int[].class),
/**
* Assume Code 39 codes employ a check digit. Doesn't matter what it maps to;
* use {@link Boolean#TRUE}.
*/
ASSUME_CODE_39_CHECK_DIGIT(Void.class),
/**
* Assume the barcode is being processed as a GS1 barcode, and modify behavior as needed.
* For example this affects FNC1 handling for Code 128 (aka GS1-128). Doesn't matter what it maps to;
* use {@link Boolean#TRUE}.
*/
ASSUME_GS1(Void.class),
/**
* The caller needs to be notified via callback when a possible {@link ResultPoint}
* is found. Maps to a {@link ResultPointCallback}.
*/
NEED_RESULT_POINT_CALLBACK(ResultPointCallback.class),
// End of enumeration values.
;
/**
* Data type the hint is expecting.
* Among the possible values the {@link Void} stands out as being used for
* hints that do not expect a value to be supplied (flag hints). Such hints
* will possibly have their value ignored, or replaced by a
* {@link Boolean#TRUE}. Hint suppliers should probably use
* {@link Boolean#TRUE} as directed by the actual hint documentation.
*/
private final Class<?> valueType;
DecodeHintType(Class<?> valueType) {
this.valueType = valueType;
}
public Class<?> getValueType() {
return valueType;
}
}
然后我们看下android里面是如何调用的,入口是CaptureActivity,在com.google.zxing.client.android package中,以下描述一个通用的流程

CaptureAct中的onResume中的initCamera初始化CaptureActHandler,其构造函数中新起了一个DecodeThread去异步准备一个DecodeHandler,然后调用restartPreviewAndDecode方法,让DecodeHandler去处理R.id.decode的消息,当然这里需要处理一些线程同步问题,代码里用到了CountDownLatch来控制。DecodeHanlder处理R.id.decode消息后用传递R.id.decode_succeeded消息给CaptureActHanlder,最终再调用handleDecode传递给CaptureAct.
zxing二维码扫描的流程简析(Android版)的更多相关文章
- Android—ZXing二维码扫描遇到的问题
最近工作中需要开发带有二维码扫描功能的软件(基于开源项目ZXing),遇到的问题记录一下,也希望给大家带来帮助. 1.首先因为扫描要开摄像机所以加权限是一定的,不然后面什么都不能进行 <uses ...
- Android之Zxing二维码扫描图片拉伸
还是这个接手项目,二维码扫描集成的是zxing,扫描界面的图像有明显的拉伸变形. 这种问题,根据以往的经验,一般是x,y轴错位引起的,处理好x,y轴的问题,一般可以解决问题. 由于这个问题,之前有很多 ...
- zxing 二维码扫描 配置和使用
本文转载至 http://blog.csdn.net/a6472953/article/details/8796501 二维码扫描使用最多的主要有两个库:zbarSDK 和zxing 关于zbar ...
- 自定义ZXing二维码扫描界面并解决取景框拉伸等问题
先看效果 扫描内容是下面这张,二维码是用zxing库生成的 由于改了好几个类,还是去年的事都忘得差不多了,所以只能上这个类的代码了,主要就是改了这个CaptureActivity.java packa ...
- Zxing二维码扫描
源代码地址 有问题能够加QQ:312122330 之前对于Zbar的二位码扫描.到项目上线以后才发现扫描过于灵敏.导致有时候扫描到半截就启动了. 后来翻看ZXING的源代码,没有想象的复杂,复杂的地 ...
- google zxing 二维码扫描(android client分析)
一.总体架构 二.架构分析 1. com.google.zxing.client.android AmbientLightManager 环境光线管理 Detects ambient light an ...
- Android快速实现二维码扫描--Zxing
Android中二维码扫描的最常用库是zxing和zbar,zxing项目地址为https://github.com/zxing/zxing,目前还有多个人在维护.zbar主要用C来写的,对速度有要求 ...
- Android 基于google Zxing实现二维码、条形码扫描,仿微信二维码扫描效果
Android 高手进阶(21) 版权声明:本文为博主原创文章,未经博主允许不得转载. 转载请注明出处:http://blog.csdn.net/xiaanming/article/detail ...
- Android自由行之走进zxing,轻松实现二维码扫描
现在很多App都集成了扫一扫功能,最常用的微信.QQ.手机助手等.二维码也使得生活变得更加简洁,扫一扫订餐.扫一扫下载等等.那么,说到二维码,我们不得不提Google一个开源的扫码框架:zxing. ...
随机推荐
- mvc5 解析route源码实现自己的route系统
Asp.net mvc5 解析route源码实现自己的route系统 url route 路由系统的责任是找到匹配的路由,创建路由数据,并将请求分配给一个处理程序. 选择动作是 MVC 的处理程序 ...
- ubuntu分屏终端
一:更新source 列表: 将/etc/apt/sources.list的镜像源改为网易源:http://mirrors.163.com/ubuntu/dists/ deb http://mirro ...
- SQL Server编程系列(2):SMO常用对象的有关操作
原文:SQL Server编程系列(2):SMO常用对象的有关操作 在上一篇周公简单讲述了SMO的一些基本概念,实际上SMO体系结构远不止周公在上一篇中讲述的那么简单,下图是MSDN上给出的一个完整的 ...
- Java数据结构与算法(13) - ch06递归(归并排序)
时间为O(N*logN). 归并排序的一个缺点是它需要在存储器中有另一个大小等于被排序的数据项数目的数组.归并两个有序的数组.利用递归,不断的将数组进行二分法排序,然后进行归并即可.
- HTTPS那个东西(一)-HTTPS原理
HTTPS那个东西(一) 最近看了<http权威指南>几个章节,对HTTPS随着节,了一些资料,遂打算记录一下心得.写的仓促,肯定有非常多错误的地方,欢迎大家指正. 1.HTTP是什么 那 ...
- ACM 入门计划
acm 本文由swellspirit贡献 ACM • I can accept failure. but I can't accept not trying. Life is often compar ...
- AlloyRenderingEngine
AlloyRenderingEngine燃烧的进度条 写在前面 Github: https://github.com/AlloyTeam/AlloyGameEngine HTML 5新增了progre ...
- 讨论IT选定的技术招聘企业几点
在实际的招聘总结的几点思考,企业需要怎么样的人才,例如,以下个人总结: 1.技术能力是不是第一次 企业的时候,你往往看第一点的人的招聘是不是技术实力.但是,你的个人言论的行为和态度.能在半个小时内把你 ...
- POJ3342——Party at Hali-Bula
Party at Hali-Bula Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 5418 Accepted: 192 ...
- 详解linux vi命令用法
vi是所有UNIX系统都会提供的屏幕编辑器,它提供了一个视窗设备,通过它可以编辑文件.当然,对UNIX系统略有所知的人,或多或少都觉得vi超级难用,但vi是最基本的编辑器,所以希望读者能好好把它学起来 ...