• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2007 ZXing authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.zxing;
18 
19 import com.google.zxing.aztec.AztecReader;
20 import com.google.zxing.datamatrix.DataMatrixReader;
21 import com.google.zxing.maxicode.MaxiCodeReader;
22 import com.google.zxing.oned.MultiFormatOneDReader;
23 import com.google.zxing.pdf417.PDF417Reader;
24 import com.google.zxing.qrcode.QRCodeReader;
25 
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.Map;
29 
30 /**
31  * MultiFormatReader is a convenience class and the main entry point into the library for most uses.
32  * By default it attempts to decode all barcode formats that the library supports. Optionally, you
33  * can provide a hints object to request different behavior, for example only decoding QR codes.
34  *
35  * @author Sean Owen
36  * @author dswitkin@google.com (Daniel Switkin)
37  */
38 public final class MultiFormatReader implements Reader {
39 
40   private static final Reader[] EMPTY_READER_ARRAY = new Reader[0];
41 
42   private Map<DecodeHintType,?> hints;
43   private Reader[] readers;
44 
45   /**
46    * This version of decode honors the intent of Reader.decode(BinaryBitmap) in that it
47    * passes null as a hint to the decoders. However, that makes it inefficient to call repeatedly.
48    * Use setHints() followed by decodeWithState() for continuous scan applications.
49    *
50    * @param image The pixel data to decode
51    * @return The contents of the image
52    * @throws NotFoundException Any errors which occurred
53    */
54   @Override
decode(BinaryBitmap image)55   public Result decode(BinaryBitmap image) throws NotFoundException {
56     setHints(null);
57     return decodeInternal(image);
58   }
59 
60   /**
61    * Decode an image using the hints provided. Does not honor existing state.
62    *
63    * @param image The pixel data to decode
64    * @param hints The hints to use, clearing the previous state.
65    * @return The contents of the image
66    * @throws NotFoundException Any errors which occurred
67    */
68   @Override
decode(BinaryBitmap image, Map<DecodeHintType,?> hints)69   public Result decode(BinaryBitmap image, Map<DecodeHintType,?> hints) throws NotFoundException {
70     setHints(hints);
71     return decodeInternal(image);
72   }
73 
74   /**
75    * Decode an image using the state set up by calling setHints() previously. Continuous scan
76    * clients will get a <b>large</b> speed increase by using this instead of decode().
77    *
78    * @param image The pixel data to decode
79    * @return The contents of the image
80    * @throws NotFoundException Any errors which occurred
81    */
decodeWithState(BinaryBitmap image)82   public Result decodeWithState(BinaryBitmap image) throws NotFoundException {
83     // Make sure to set up the default state so we don't crash
84     if (readers == null) {
85       setHints(null);
86     }
87     return decodeInternal(image);
88   }
89 
90   /**
91    * This method adds state to the MultiFormatReader. By setting the hints once, subsequent calls
92    * to decodeWithState(image) can reuse the same set of readers without reallocating memory. This
93    * is important for performance in continuous scan clients.
94    *
95    * @param hints The set of hints to use for subsequent calls to decode(image)
96    */
setHints(Map<DecodeHintType,?> hints)97   public void setHints(Map<DecodeHintType,?> hints) {
98     this.hints = hints;
99 
100     boolean tryHarder = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER);
101     @SuppressWarnings("unchecked")
102     Collection<BarcodeFormat> formats =
103         hints == null ? null : (Collection<BarcodeFormat>) hints.get(DecodeHintType.POSSIBLE_FORMATS);
104     Collection<Reader> readers = new ArrayList<>();
105     if (formats != null) {
106       boolean addOneDReader =
107           formats.contains(BarcodeFormat.UPC_A) ||
108           formats.contains(BarcodeFormat.UPC_E) ||
109           formats.contains(BarcodeFormat.EAN_13) ||
110           formats.contains(BarcodeFormat.EAN_8) ||
111           formats.contains(BarcodeFormat.CODABAR) ||
112           formats.contains(BarcodeFormat.CODE_39) ||
113           formats.contains(BarcodeFormat.CODE_93) ||
114           formats.contains(BarcodeFormat.CODE_128) ||
115           formats.contains(BarcodeFormat.ITF) ||
116           formats.contains(BarcodeFormat.RSS_14) ||
117           formats.contains(BarcodeFormat.RSS_EXPANDED);
118       // Put 1D readers upfront in "normal" mode
119       if (addOneDReader && !tryHarder) {
120         readers.add(new MultiFormatOneDReader(hints));
121       }
122       if (formats.contains(BarcodeFormat.QR_CODE)) {
123         readers.add(new QRCodeReader());
124       }
125       if (formats.contains(BarcodeFormat.DATA_MATRIX)) {
126         readers.add(new DataMatrixReader());
127       }
128       if (formats.contains(BarcodeFormat.AZTEC)) {
129         readers.add(new AztecReader());
130       }
131       if (formats.contains(BarcodeFormat.PDF_417)) {
132         readers.add(new PDF417Reader());
133       }
134       if (formats.contains(BarcodeFormat.MAXICODE)) {
135         readers.add(new MaxiCodeReader());
136       }
137       // At end in "try harder" mode
138       if (addOneDReader && tryHarder) {
139         readers.add(new MultiFormatOneDReader(hints));
140       }
141     }
142     if (readers.isEmpty()) {
143       if (!tryHarder) {
144         readers.add(new MultiFormatOneDReader(hints));
145       }
146 
147       readers.add(new QRCodeReader());
148       readers.add(new DataMatrixReader());
149       readers.add(new AztecReader());
150       readers.add(new PDF417Reader());
151       readers.add(new MaxiCodeReader());
152 
153       if (tryHarder) {
154         readers.add(new MultiFormatOneDReader(hints));
155       }
156     }
157     this.readers = readers.toArray(EMPTY_READER_ARRAY);
158   }
159 
160   @Override
reset()161   public void reset() {
162     if (readers != null) {
163       for (Reader reader : readers) {
164         reader.reset();
165       }
166     }
167   }
168 
decodeInternal(BinaryBitmap image)169   private Result decodeInternal(BinaryBitmap image) throws NotFoundException {
170     if (readers != null) {
171       for (Reader reader : readers) {
172         if (Thread.currentThread().isInterrupted()) {
173           throw NotFoundException.getNotFoundInstance();
174         }
175         try {
176           return reader.decode(image, hints);
177         } catch (ReaderException re) {
178           // continue
179         }
180       }
181       if (hints != null && hints.containsKey(DecodeHintType.ALSO_INVERTED)) {
182         // Calling all readers again with inverted image
183         image.getBlackMatrix().flip();
184         for (Reader reader : readers) {
185           if (Thread.currentThread().isInterrupted()) {
186             throw NotFoundException.getNotFoundInstance();
187           }
188           try {
189             return reader.decode(image, hints);
190           } catch (ReaderException re) {
191             // continue
192           }
193         }
194       }
195     }
196     throw NotFoundException.getNotFoundInstance();
197   }
198 
199 }
200