Skip to main content

rxing/
multi_use_multi_format_reader.rs

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
17use std::collections::HashSet;
18
19use crate::DecodeHints;
20use crate::common::Result;
21use crate::qrcode::cpp_port::QrReader;
22use crate::{
23    BarcodeFormat, Binarizer, BinaryBitmap, Exceptions, RXingResult, Reader, aztec::AztecReader,
24    datamatrix::DataMatrixReader, maxicode::MaxiCodeReader, oned::MultiFormatOneDReader,
25    pdf417::PDF417Reader, qrcode::QRCodeReader,
26};
27
28pub(crate) const ONE_D_FORMATS: [BarcodeFormat; 12] = [
29    BarcodeFormat::UPC_A,
30    BarcodeFormat::UPC_E,
31    BarcodeFormat::EAN_13,
32    BarcodeFormat::EAN_8,
33    BarcodeFormat::CODABAR,
34    BarcodeFormat::CODE_39,
35    BarcodeFormat::CODE_93,
36    BarcodeFormat::CODE_128,
37    BarcodeFormat::ITF,
38    BarcodeFormat::RSS_14,
39    BarcodeFormat::RSS_EXPANDED,
40    BarcodeFormat::TELEPEN,
41];
42
43/**
44 * MultiFormatReader is a convenience class and the main entry point into the library for most uses.
45 * By default it attempts to decode all barcode formats that the library supports. Optionally, you
46 * can provide a hints object to request different behavior, for example only decoding QR codes.
47 *
48 * @author Sean Owen
49 * @author dswitkin@google.com (Daniel Switkin)
50 */
51#[derive(Default)]
52pub struct MultiUseMultiFormatReader {
53    hints: DecodeHints,
54    possible_formats: HashSet<BarcodeFormat>,
55    try_harder: bool,
56    one_d_reader: MultiFormatOneDReader,
57    qr_code_reader: QRCodeReader,
58    data_matrix_reader: DataMatrixReader,
59    aztec_reader: AztecReader,
60    pdf417_reader: PDF417Reader,
61    maxicode_reader: MaxiCodeReader,
62    cpp_qrcode_reader: QrReader,
63}
64
65impl Reader for MultiUseMultiFormatReader {
66    /**
67     * This version of decode honors the intent of Reader.decode(BinaryBitmap) in that it
68     * passes null as a hint to the decoders. However, that makes it inefficient to call repeatedly.
69     * Use setHints() followed by decodeWithState() for continuous scan applications.
70     *
71     * @param image The pixel data to decode
72     * @return The contents of the image
73     * @throws NotFoundException Any errors which occurred
74     */
75    fn decode<B: Binarizer>(&mut self, image: &mut BinaryBitmap<B>) -> Result<RXingResult> {
76        self.set_hints(&DecodeHints::default());
77        self.decode_internal(image)
78    }
79
80    /**
81     * Decode an image using the hints provided. Does not honor existing state.
82     *
83     * @param image The pixel data to decode
84     * @param hints The hints to use, clearing the previous state.
85     * @return The contents of the image
86     * @throws NotFoundException Any errors which occurred
87     */
88    fn decode_with_hints<B: Binarizer>(
89        &mut self,
90        image: &mut BinaryBitmap<B>,
91        hints: &DecodeHints,
92    ) -> Result<RXingResult> {
93        self.set_hints(hints);
94        self.decode_internal(image)
95    }
96
97    fn reset(&mut self) {
98        self.one_d_reader.reset();
99        self.qr_code_reader.reset();
100        self.data_matrix_reader.reset();
101        self.aztec_reader.reset();
102        self.pdf417_reader.reset();
103        self.maxicode_reader.reset();
104        self.cpp_qrcode_reader.reset();
105    }
106}
107
108impl MultiUseMultiFormatReader {
109    /**
110     * Decode an image using the state set up by calling setHints() previously. Continuous scan
111     * clients will get a <b>large</b> speed increase by using this instead of decode().
112     *
113     * @param image The pixel data to decode
114     * @return The contents of the image
115     * @throws NotFoundException Any errors which occurred
116     */
117    pub fn decode_with_state<B: Binarizer>(
118        &mut self,
119        image: &mut BinaryBitmap<B>,
120    ) -> Result<RXingResult> {
121        // Make sure to set up the default state so we don't crash
122        if self.possible_formats.is_empty() {
123            self.set_hints(&DecodeHints::default());
124        }
125        self.decode_internal(image)
126    }
127
128    /**
129     * This method adds state to the MultiFormatReader. By setting the hints once, subsequent calls
130     * to decodeWithState(image) can reuse the same set of readers without reallocating memory. This
131     * is important for performance in continuous scan clients.
132     *
133     * @param hints The set of hints to use for subsequent calls to decode(image)
134     */
135    pub fn set_hints(&mut self, hints: &DecodeHints) {
136        self.hints.clone_from(hints);
137
138        self.try_harder = matches!(self.hints.TryHarder, Some(true));
139        self.possible_formats = if let Some(formats) = &hints.PossibleFormats {
140            formats.clone()
141        } else {
142            HashSet::new()
143        };
144        self.one_d_reader = MultiFormatOneDReader::new(hints);
145    }
146
147    pub fn decode_internal<B: Binarizer>(
148        &mut self,
149        image: &mut BinaryBitmap<B>,
150    ) -> Result<RXingResult> {
151        let res = self.decode_formats(image);
152        if res.is_ok() {
153            return res;
154        }
155        if matches!(self.hints.AlsoInverted, Some(true)) {
156            // Calling all readers again with inverted image
157            image.get_black_matrix_mut().flip_self();
158            let res = self.decode_formats(image);
159            if let Ok(mut r) = res {
160                // let mut r = res.unwrap();
161                r.putMetadata(
162                    crate::RXingResultMetadataType::IS_INVERTED,
163                    crate::RXingResultMetadataValue::IsInverted(true),
164                );
165                return Ok(r);
166            }
167            // if res.is_ok() {
168            //     return res;
169            // }
170        }
171        Err(Exceptions::NOT_FOUND)
172    }
173
174    fn decode_formats<B: Binarizer>(&mut self, image: &mut BinaryBitmap<B>) -> Result<RXingResult> {
175        if !self.possible_formats.is_empty() {
176            let one_d = ONE_D_FORMATS
177                .iter()
178                .any(|e| self.possible_formats.contains(e));
179            // let one_d = self.possible_formats.contains(&BarcodeFormat::UPC_A)
180            //     || self.possible_formats.contains(&BarcodeFormat::UPC_E)
181            //     || self.possible_formats.contains()
182            //     || self.possible_formats.contains()
183            //     || self.possible_formats.contains()
184            //     || self.possible_formats.contains()
185            //     || self.possible_formats.contains()
186            //     || self.possible_formats.contains()
187            //     || self.possible_formats.contains()
188            //     || self.possible_formats.contains()
189            //     || self.possible_formats.contains()
190            //     || self.possible_formats.contains();
191            if one_d && !self.try_harder {
192                if let Ok(res) = self.one_d_reader.decode_with_hints(image, &self.hints) {
193                    return Ok(res);
194                }
195            }
196            for possible_format in self.possible_formats.iter() {
197                let res = match possible_format {
198                    BarcodeFormat::QR_CODE => {
199                        let a = self.cpp_qrcode_reader.decode_with_hints(image, &self.hints);
200                        if a.is_ok() {
201                            a
202                        } else {
203                            self.qr_code_reader.decode_with_hints(image, &self.hints)
204                        }
205                    }
206                    BarcodeFormat::MICRO_QR_CODE => {
207                        self.cpp_qrcode_reader.decode_with_hints(image, &self.hints)
208                    }
209                    BarcodeFormat::DATA_MATRIX => self
210                        .data_matrix_reader
211                        .decode_with_hints(image, &self.hints),
212                    BarcodeFormat::AZTEC => self.aztec_reader.decode_with_hints(image, &self.hints),
213                    BarcodeFormat::PDF_417 => {
214                        self.pdf417_reader.decode_with_hints(image, &self.hints)
215                    }
216                    BarcodeFormat::MAXICODE => {
217                        self.maxicode_reader.decode_with_hints(image, &self.hints)
218                    }
219                    _ => Err(Exceptions::UNSUPPORTED_OPERATION),
220                };
221                if res.is_ok() {
222                    return res;
223                }
224            }
225            if one_d && self.try_harder {
226                if let Ok(res) = self.one_d_reader.decode_with_hints(image, &self.hints) {
227                    return Ok(res);
228                }
229            }
230        } else {
231            if !self.try_harder {
232                if let Ok(res) = self.one_d_reader.decode_with_hints(image, &self.hints) {
233                    return Ok(res);
234                }
235            }
236            if let Ok(res) = self.cpp_qrcode_reader.decode_with_hints(image, &self.hints) {
237                return Ok(res);
238            }
239            if let Ok(res) = self.qr_code_reader.decode_with_hints(image, &self.hints) {
240                return Ok(res);
241            }
242            if let Ok(res) = self
243                .data_matrix_reader
244                .decode_with_hints(image, &self.hints)
245            {
246                return Ok(res);
247            }
248            if let Ok(res) = self.aztec_reader.decode_with_hints(image, &self.hints) {
249                return Ok(res);
250            }
251            if let Ok(res) = self.pdf417_reader.decode_with_hints(image, &self.hints) {
252                return Ok(res);
253            }
254            if let Ok(res) = self.maxicode_reader.decode_with_hints(image, &self.hints) {
255                return Ok(res);
256            }
257
258            if self.try_harder {
259                if let Ok(res) = self.one_d_reader.decode_with_hints(image, &self.hints) {
260                    return Ok(res);
261                }
262            }
263        }
264
265        Err(Exceptions::UNSUPPORTED_OPERATION)
266    }
267}