zoukankan      html  css  js  c++  java
  • zxing二维码扫描的流程简析(Android版)

    目前市面上二维码的扫描似乎用开源google的zxing比较多,接下去以2.2版本做一个简析吧,勿喷。。。

    下载下来后定位两个文件夹,core和android,core是一些核心的库,android是针对android的一些代码。

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

    接口Writer里面有两个encode的重载函数,不同的格式的二维码有各自的类实现了Writer接口,MultiformatWriter类比较特殊,根据代码的注释可见其其实是个工厂类,根据BarcodeFormat实例化不同的Writer,然后最终调用各自的Encode.encode()方法

     1 public final class MultiFormatWriter implements Writer {
     2 
     3   @Override
     4   public BitMatrix encode(String contents,
     5                           BarcodeFormat format,
     6                           int width,
     7                           int height) throws WriterException {
     8     return encode(contents, format, width, height, null);
     9   }
    10 
    11   @Override
    12   public BitMatrix encode(String contents,
    13                           BarcodeFormat format,
    14                           int width, int height,
    15                           Map<EncodeHintType,?> hints) throws WriterException {
    16 
    17     Writer writer;
    18     switch (format) {
    19       case EAN_8:
    20         writer = new EAN8Writer();
    21         break;
    22       case EAN_13:
    23         writer = new EAN13Writer();
    24         break;
    25       case UPC_A:
    26         writer = new UPCAWriter();
    27         break;
    28       case QR_CODE:
    29         writer = new QRCodeWriter();
    30         break;
    31       case CODE_39:
    32         writer = new Code39Writer();
    33         break;
    34       case CODE_128:
    35         writer = new Code128Writer();
    36         break;
    37       case ITF:
    38         writer = new ITFWriter();
    39         break;
    40       case PDF_417:
    41         writer = new PDF417Writer();
    42         break;
    43       case CODABAR:
    44         writer = new CodaBarWriter();
    45         break;
    46       case DATA_MATRIX:
    47         writer = new DataMatrixWriter();
    48         break;
    49       case AZTEC:
    50         writer = new AztecWriter();
    51         break;
    52       default:
    53         throw new IllegalArgumentException("No encoder available for format " + format);
    54     }
    55     return writer.encode(contents, format, width, height, hints);
    56   }
    57 
    58 }

    然后看解析二维码的类结构

    关键就是这个MultiformatReader,里面聚合了多个reader,并且根据客户端设置的DecodeHintType值,确定添加reader以及添加reader的顺序,最后调用reader.decode方法

      1 public final class MultiFormatReader implements Reader {
      2 
      3   private Map<DecodeHintType,?> hints;
      4   private Reader[] readers;
      5 
      6   @Override
      7   public Result decode(BinaryBitmap image) throws NotFoundException {
      8     setHints(null);
      9     return decodeInternal(image);
     10   }
     11 
     12   @Override
     13   public Result decode(BinaryBitmap image, Map<DecodeHintType,?> hints) throws NotFoundException {
     14     setHints(hints);
     15     return decodeInternal(image);
     16   }
     17 
     18   public Result decodeWithState(BinaryBitmap image) throws NotFoundException {
     19     // Make sure to set up the default state so we don't crash
     20     if (readers == null) {
     21       setHints(null);
     22     }
     23     return decodeInternal(image);
     24   }
     25 
     26   public void setHints(Map<DecodeHintType,?> hints) {//根据设置的hint来设置reader
     27     this.hints = hints;
     28 
     29     boolean tryHarder = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER);
     30     @SuppressWarnings("unchecked")
     31     Collection<BarcodeFormat> formats =
     32         hints == null ? null : (Collection<BarcodeFormat>) hints.get(DecodeHintType.POSSIBLE_FORMATS);
     33     Collection<Reader> readers = new ArrayList<Reader>();
     34     if (formats != null) {
     35       boolean addOneDReader =
     36           formats.contains(BarcodeFormat.UPC_A) ||
     37           formats.contains(BarcodeFormat.UPC_E) ||
     38           formats.contains(BarcodeFormat.EAN_13) ||
     39           formats.contains(BarcodeFormat.EAN_8) ||
     40           formats.contains(BarcodeFormat.CODABAR) ||
     41           formats.contains(BarcodeFormat.CODE_39) ||
     42           formats.contains(BarcodeFormat.CODE_93) ||
     43           formats.contains(BarcodeFormat.CODE_128) ||
     44           formats.contains(BarcodeFormat.ITF) ||
     45           formats.contains(BarcodeFormat.RSS_14) ||
     46           formats.contains(BarcodeFormat.RSS_EXPANDED);
     47       // Put 1D readers upfront in "normal" mode
     48       if (addOneDReader && !tryHarder) {
     49         readers.add(new MultiFormatOneDReader(hints));
     50       }
     51       if (formats.contains(BarcodeFormat.QR_CODE)) {
     52         readers.add(new QRCodeReader());
     53       }
     54       if (formats.contains(BarcodeFormat.DATA_MATRIX)) {
     55         readers.add(new DataMatrixReader());
     56       }
     57       if (formats.contains(BarcodeFormat.AZTEC)) {
     58         readers.add(new AztecReader());
     59       }
     60       if (formats.contains(BarcodeFormat.PDF_417)) {
     61          readers.add(new PDF417Reader());
     62       }
     63       if (formats.contains(BarcodeFormat.MAXICODE)) {
     64          readers.add(new MaxiCodeReader());
     65       }
     66       // At end in "try harder" mode
     67       if (addOneDReader && tryHarder) {
     68         readers.add(new MultiFormatOneDReader(hints));
     69       }
     70     }
     71     if (readers.isEmpty()) {
     72       if (!tryHarder) {
     73         readers.add(new MultiFormatOneDReader(hints));
     74       }
     75 
     76       readers.add(new QRCodeReader());
     77       readers.add(new DataMatrixReader());
     78       readers.add(new AztecReader());
     79       readers.add(new PDF417Reader());
     80       readers.add(new MaxiCodeReader());
     81 
     82       if (tryHarder) {
     83         readers.add(new MultiFormatOneDReader(hints));
     84       }
     85     }
     86     this.readers = readers.toArray(new Reader[readers.size()]);
     87   }
     88 
     89   @Override
     90   public void reset() {
     91     if (readers != null) {
     92       for (Reader reader : readers) {
     93         reader.reset();
     94       }
     95     }
     96   }
     97 
     98   private Result decodeInternal(BinaryBitmap image) throws NotFoundException {//最终都调用这个方法
     99     if (readers != null) {
    100       for (Reader reader : readers) {
    101         try {
    102           return reader.decode(image, hints);
    103         } catch (ReaderException re) {
    104           // continue
    105         }
    106       }
    107     }
    108     throw NotFoundException.getNotFoundInstance();
    109   }
    110 
    111 }

    DecodeHintType的语法比较有意思,还在理解中

     1 public enum DecodeHintType {
     2 
     3   /**
     4    * Unspecified, application-specific hint. Maps to an unspecified {@link Object}.
     5    */
     6  OTHER(Object.class),
     7 
     8   /**
     9    * Image is a pure monochrome image of a barcode. Doesn't matter what it maps to;
    10    * use {@link Boolean#TRUE}.
    11    */
    12   PURE_BARCODE(Void.class),
    13 
    14   /**
    15    * Image is known to be of one of a few possible formats.
    16    * Maps to a {@link List} of {@link BarcodeFormat}s.
    17    */
    18   POSSIBLE_FORMATS(List.class),
    19 
    20   /**
    21    * Spend more time to try to find a barcode; optimize for accuracy, not speed.
    22    * Doesn't matter what it maps to; use {@link Boolean#TRUE}.
    23    */
    24   TRY_HARDER(Void.class),
    25 
    26   /**
    27    * Specifies what character encoding to use when decoding, where applicable (type String)
    28    */
    29   CHARACTER_SET(String.class),
    30 
    31   /**
    32    * Allowed lengths of encoded data -- reject anything else. Maps to an {@code int[]}.
    33    */
    34   ALLOWED_LENGTHS(int[].class),
    35 
    36   /**
    37    * Assume Code 39 codes employ a check digit. Doesn't matter what it maps to;
    38    * use {@link Boolean#TRUE}.
    39    */
    40   ASSUME_CODE_39_CHECK_DIGIT(Void.class),
    41 
    42   /**
    43    * Assume the barcode is being processed as a GS1 barcode, and modify behavior as needed.
    44    * For example this affects FNC1 handling for Code 128 (aka GS1-128). Doesn't matter what it maps to;
    45    * use {@link Boolean#TRUE}.
    46    */
    47   ASSUME_GS1(Void.class),
    48 
    49   /**
    50    * The caller needs to be notified via callback when a possible {@link ResultPoint}
    51    * is found. Maps to a {@link ResultPointCallback}.
    52    */
    53   NEED_RESULT_POINT_CALLBACK(ResultPointCallback.class),
    54 
    55   // End of enumeration values.
    56   ;
    57 
    58   /**
    59    * Data type the hint is expecting.
    60    * Among the possible values the {@link Void} stands out as being used for
    61    * hints that do not expect a value to be supplied (flag hints). Such hints
    62    * will possibly have their value ignored, or replaced by a
    63    * {@link Boolean#TRUE}. Hint suppliers should probably use
    64    * {@link Boolean#TRUE} as directed by the actual hint documentation.
    65    */
    66   private final Class<?> valueType;
    67 
    68   DecodeHintType(Class<?> valueType) {
    69     this.valueType = valueType;
    70   }
    71   
    72   public Class<?> getValueType() {
    73     return valueType;
    74   }
    75 
    76 }

    然后我们看下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.

  • 相关阅读:
    linux安装
    ajax基础------备忘
    jquery简单入门1
    在jsp页面如何获得url参数
    MySQL外键设置中的的 Cascade、NO ACTION、Restrict、SET NULL
    springmvc.xml和applicationContext.xml配置的特点
    1.更改当前工作目录
    0.学习资料
    13.git别名
    12.打标签
  • 原文地址:https://www.cnblogs.com/cqcmdwym/p/3297073.html
Copyright © 2011-2022 走看看