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