dabecc2899af64086de1189e6035d3a82ff50fe5
[zxing.git] / core / src / com / google / zxing / MultiFormatReader.java
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.oned.MultiFormatOneDReader;
20 import com.google.zxing.qrcode.QRCodeReader;
21
22 import java.util.Hashtable;
23 import java.util.Vector;
24
25 /**
26  * MultiFormatReader is a convenience class and the main entry point into the library for most uses.
27  * By default it attempts to decode all barcode formats that the library supports. Optionally, you
28  * can provide a hints object to request different behavior, for example only decoding QR codes.
29  *
30  * @author Sean Owen
31  * @author dswitkin@google.com (Daniel Switkin)
32  */
33 public final class MultiFormatReader implements Reader {
34
35   private Hashtable hints;
36   private Vector readers;
37
38   /**
39    * This version of decode honors the intent of Reader.decode(MonochromeBitmapSource) in that it
40    * passes null as a hint to the decoders. However, that makes it inefficient to call repeatedly.
41    * Use setHints() followed by decodeWithState() for continuous scan applications.
42    *
43    * @param image The pixel data to decode
44    * @return The contents of the image
45    * @throws ReaderException Any errors which occurred
46    */
47   public Result decode(MonochromeBitmapSource image) throws ReaderException {
48     setHints(null);
49     return decodeInternal(image);
50   }
51
52   /**
53    * Decode an image using the hints provided. Does not honor existing state.
54    *
55    * @param image The pixel data to decode
56    * @param hints The hints to use, clearing the previous state.
57    * @return The contents of the image
58    * @throws ReaderException Any errors which occurred
59    */
60   public Result decode(MonochromeBitmapSource image, Hashtable hints) throws ReaderException {
61     setHints(hints);
62     return decodeInternal(image);
63   }
64
65   /**
66    * Decode an image using the state set up by calling setHints() previously. Continuous scan
67    * clients will get a <b>large</b> speed increase by using this instead of decode().
68    *
69    * @param image The pixel data to decode
70    * @return The contents of the image
71    * @throws ReaderException Any errors which occurred
72    */
73   public Result decodeWithState(MonochromeBitmapSource image) throws ReaderException {
74     // Make sure to set up the default state so we don't crash
75     if (readers == null) {
76       setHints(null);
77     }
78     return decodeInternal(image);
79   }
80
81   /**
82    * This method adds state to the MultiFormatReader. By setting the hints once, subsequent calls
83    * to decodeWithState(image) can reuse the same set of readers without reallocating memory. This
84    * is important for performance in continuous scan clients.
85    *
86    * @param hints The set of hints to use for subsequent calls to decode(image)
87    */
88   public void setHints(Hashtable hints) {
89     this.hints = hints;
90
91     boolean tryHarder = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER);
92     Vector possibleFormats = hints == null ? null : (Vector) hints.get(DecodeHintType.POSSIBLE_FORMATS);
93     readers = new Vector();
94     if (possibleFormats != null) {
95       boolean addOneDReader =
96           possibleFormats.contains(BarcodeFormat.UPC_A) ||
97               possibleFormats.contains(BarcodeFormat.UPC_E) ||
98               possibleFormats.contains(BarcodeFormat.EAN_13) ||
99               possibleFormats.contains(BarcodeFormat.EAN_8) ||
100               possibleFormats.contains(BarcodeFormat.CODE_39) ||
101               possibleFormats.contains(BarcodeFormat.CODE_128) ||
102               possibleFormats.contains(BarcodeFormat.ITF);
103       // Put 1D readers upfront in "normal" mode
104       if (addOneDReader && !tryHarder) {
105         readers.addElement(new MultiFormatOneDReader(hints));
106       }
107       if (possibleFormats.contains(BarcodeFormat.QR_CODE)) {
108         readers.addElement(new QRCodeReader());
109       }
110       // TODO re-enable once Data Matrix is ready
111       //if (possibleFormats.contains(BarcodeFormat.DATAMATRIX)) {
112       //  readers.addElement(new DataMatrixReader());
113       //}
114       // At end in "try harder" mode
115       if (addOneDReader && tryHarder) {
116         readers.addElement(new MultiFormatOneDReader(hints));
117       }
118     }
119     if (readers.isEmpty()) {
120       if (!tryHarder) {
121         readers.addElement(new MultiFormatOneDReader(hints));
122       }
123       readers.addElement(new QRCodeReader());
124       // TODO re-enable once Data Matrix is ready
125       // readers.addElement(new DataMatrixReader());
126       if (tryHarder) {
127         readers.addElement(new MultiFormatOneDReader(hints));
128       }
129     }
130   }
131
132   private Result decodeInternal(MonochromeBitmapSource image) throws ReaderException {
133     int size = readers.size();
134     for (int i = 0; i < size; i++) {
135       Reader reader = (Reader) readers.elementAt(i);
136       try {
137         return reader.decode(image, hints);
138       } catch (ReaderException re) {
139         // continue
140       }
141     }
142
143     throw ReaderException.getInstance();
144   }
145
146 }