204952796a7a32b6db336bcd0b253748b7f9c766
[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       // Put 1D readers upfront in "normal" mode
103       if (addOneDReader && !tryHarder) {
104         readers.addElement(new MultiFormatOneDReader(hints));
105       }
106       if (possibleFormats.contains(BarcodeFormat.QR_CODE)) {
107         readers.addElement(new QRCodeReader());
108       }
109       // TODO re-enable once Data Matrix is ready
110       //if (possibleFormats.contains(BarcodeFormat.DATAMATRIX)) {
111       //  readers.addElement(new DataMatrixReader());
112       //}
113       // At end in "try harder" mode
114       if (addOneDReader && tryHarder) {
115         readers.addElement(new MultiFormatOneDReader(hints));
116       }
117     }
118     if (readers.isEmpty()) {
119       if (!tryHarder) {
120         readers.addElement(new MultiFormatOneDReader(hints));
121       }
122       readers.addElement(new QRCodeReader());
123       // TODO re-enable once Data Matrix is ready
124       // readers.addElement(new DataMatrixReader());
125       if (tryHarder) {
126         readers.addElement(new MultiFormatOneDReader(hints));
127       }
128     }
129   }
130
131   private Result decodeInternal(MonochromeBitmapSource image) throws ReaderException {
132     int size = readers.size();
133     for (int i = 0; i < size; i++) {
134       Reader reader = (Reader) readers.elementAt(i);
135       try {
136         return reader.decode(image, hints);
137       } catch (ReaderException re) {
138         // continue
139       }
140     }
141
142     throw ReaderException.getInstance();
143   }
144
145 }