Skip to main content

rxing/
decode_hints.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
17//package com.google.zxing;
18
19use std::collections::{HashMap, HashSet};
20
21use crate::{BarcodeFormat, PointCallback};
22
23#[cfg(feature = "serde")]
24use serde::{Deserialize, Serialize};
25
26/**
27 * Encapsulates a type of hint that a caller may pass to a barcode reader to help it
28 * more quickly or accurately decode it. It is up to implementations to decide what,
29 * if anything, to do with the information that is supplied.
30 *
31 * @author Sean Owen
32 * @author dswitkin@google.com (Daniel Switkin)
33 * @see Reader#decode(BinaryBitmap,java.util.Map)
34 */
35#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
36#[derive(Eq, PartialEq, Hash, Debug, Clone, Copy)]
37pub enum DecodeHintType {
38    /**
39     * Unspecified, application-specific hint. Maps to an unspecified {@link Object}.
40     */
41    OTHER,
42
43    /**
44     * Image is a pure monochrome image of a barcode. Doesn't matter what it maps to;
45     * use {@link Boolean#TRUE}.
46     */
47    PURE_BARCODE,
48
49    /**
50     * Image is known to be of one of a few possible formats.
51     * Maps to a {@link List} of {@link BarcodeFormat}s.
52     */
53    POSSIBLE_FORMATS,
54
55    /**
56     * Spend more time to try to find a barcode; optimize for accuracy, not speed.
57     * Doesn't matter what it maps to; use {@link Boolean#TRUE}.
58     */
59    TRY_HARDER,
60
61    /**
62     * Specifies what character encoding to use when decoding, where applicable (type String)
63     */
64    CHARACTER_SET,
65
66    /**
67     * Allowed lengths of encoded data -- reject anything else. Maps to an {@code int[]}.
68     */
69    ALLOWED_LENGTHS,
70
71    /**
72     * Assume Code 39 codes employ a check digit. Doesn't matter what it maps to;
73     * use {@link Boolean#TRUE}.
74     */
75    ASSUME_CODE_39_CHECK_DIGIT,
76
77    /**
78     * Assume the barcode is being processed as a GS1 barcode, and modify behavior as needed.
79     * For example this affects FNC1 handling for Code 128 (aka GS1-128). Doesn't matter what it maps to;
80     * use {@link Boolean#TRUE}.
81     */
82    ASSUME_GS1,
83
84    /**
85     * If true, return the start and end digits in a Codabar barcode instead of stripping them. They
86     * are alpha, whereas the rest are numeric. By default, they are stripped, but this causes them
87     * to not be. Doesn't matter what it maps to; use {@link Boolean#TRUE}.
88     */
89    RETURN_CODABAR_START_END,
90
91    /**
92     * The caller needs to be notified via callback when a possible {@link Point}
93     * is found. Maps to a {@link PointCallback}.
94     */
95    NEED_RESULT_POINT_CALLBACK,
96
97    /**
98     * Allowed extension lengths for EAN or UPC barcodes. Other formats will ignore this.
99     * Maps to an {@code int[]} of the allowed extension lengths, for example [2], [5], or [2, 5].
100     * If it is optional to have an extension, do not set this hint. If this is set,
101     * and a UPC or EAN barcode is found but an extension is not, then no result will be returned
102     * at all.
103     */
104    ALLOWED_EAN_EXTENSIONS,
105
106    /**
107     * If true, also tries to decode as inverted image. All configured decoders are simply called a
108     * second time with an inverted image. Doesn't matter what it maps to; use {@link Boolean#TRUE}.
109     */
110    ALSO_INVERTED,
111
112    /**
113     * Specifies that the codes are expected to be in conformance with the specification
114     * ISO/IEC 18004 regading the interpretation of character encoding. Values encoded in BYTE mode
115     * or in KANJI mode are interpreted as ISO-8859-1 characters unless an ECI specified at a prior
116     * location in the input specified a different encoding. By default the encoding of BYTE encoded
117     * values is determinied by the {@link #CHARACTER_SET} hint or otherwise by a heuristic that
118     * examines the bytes. By default KANJI encoded values are interpreted as the bytes of Shift-JIS
119     * encoded characters (note that this is the case even if an ECI specifies a different
120     * encoding).
121     */
122    #[cfg(feature = "allow_forced_iso_ied_18004_compliance")]
123    QR_ASSUME_SPEC_CONFORM_INPUT,
124
125    /*
126     * Will translate the ASCII values parsed by the Telepen reader into the Telepen Numeric form.
127     */
128    TELEPEN_AS_NUMERIC,
129    /*
130     * Data type the hint is expecting.
131     * Among the possible values the {@link Void} stands out as being used for
132     * hints that do not expect a value to be supplied (flag hints). Such hints
133     * will possibly have their value ignored, or replaced by a
134     * {@link Boolean#TRUE}. Hint suppliers should probably use
135     * {@link Boolean#TRUE} as directed by the actual hint documentation.
136     */
137    /*
138    private final Class<?> valueType;
139
140    DecodeHintType(Class<?> valueType) {
141      this.valueType = valueType;
142    }
143
144    public Class<?> getValueType() {
145      return valueType;
146    }*/
147}
148
149#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
150#[derive(Clone)]
151pub enum DecodeHintValue {
152    /**
153     * Unspecified, application-specific hint. Maps to an unspecified {@link Object}.
154     */
155    Other(String),
156
157    /**
158     * Image is a pure monochrome image of a barcode. Doesn't matter what it maps to;
159     * use {@link Boolean#TRUE}.
160     */
161    PureBarcode(bool),
162
163    /**
164     * Image is known to be of one of a few possible formats.
165     * Maps to a {@link List} of {@link BarcodeFormat}s.
166     */
167    PossibleFormats(HashSet<BarcodeFormat>),
168
169    /**
170     * Spend more time to try to find a barcode; optimize for accuracy, not speed.
171     * Doesn't matter what it maps to; use {@link Boolean#TRUE}.
172     */
173    TryHarder(bool),
174
175    /**
176     * Specifies what character encoding to use when decoding, where applicable (type String)
177     */
178    CharacterSet(String),
179
180    /**
181     * Allowed lengths of encoded data -- reject anything else. Maps to an {@code int[]}.
182     */
183    AllowedLengths(Vec<u32>),
184
185    /**
186     * Assume Code 39 codes employ a check digit. Doesn't matter what it maps to;
187     * use {@link Boolean#TRUE}.
188     */
189    AssumeCode39CheckDigit(bool),
190
191    /**
192     * Assume the barcode is being processed as a GS1 barcode, and modify behavior as needed.
193     * For example this affects FNC1 handling for Code 128 (aka GS1-128). Doesn't matter what it maps to;
194     * use {@link Boolean#TRUE}.
195     */
196    AssumeGs1(bool),
197
198    /**
199     * If true, return the start and end digits in a Codabar barcode instead of stripping them. They
200     * are alpha, whereas the rest are numeric. By default, they are stripped, but this causes them
201     * to not be. Doesn't matter what it maps to; use {@link Boolean#TRUE}.
202     */
203    ReturnCodabarStartEnd(bool),
204
205    /**
206     * The caller needs to be notified via callback when a possible {@link Point}
207     * is found. Maps to a {@link PointCallback}.
208     */
209    #[cfg_attr(feature = "serde", serde(skip_serializing, skip_deserializing))]
210    NeedResultPointCallback(PointCallback),
211
212    /**
213     * Allowed extension lengths for EAN or UPC barcodes. Other formats will ignore this.
214     * Maps to an {@code int[]} of the allowed extension lengths, for example [2], [5], or [2, 5].
215     * If it is optional to have an extension, do not set this hint. If this is set,
216     * and a UPC or EAN barcode is found but an extension is not, then no result will be returned
217     * at all.
218     */
219    AllowedEanExtensions(Vec<u32>),
220
221    /**
222     * If true, also tries to decode as inverted image. All configured decoders are simply called a
223     * second time with an inverted image. Doesn't matter what it maps to; use {@link Boolean#TRUE}.
224     */
225    AlsoInverted(bool),
226
227    /**
228     * Specifies that the codes are expected to be in conformance with the specification
229     * ISO/IEC 18004 regading the interpretation of character encoding. Values encoded in BYTE mode
230     * or in KANJI mode are interpreted as ISO-8859-1 characters unless an ECI specified at a prior
231     * location in the input specified a different encoding. By default the encoding of BYTE encoded
232     * values is determinied by the {@link #CHARACTER_SET} hint or otherwise by a heuristic that
233     * examines the bytes. By default KANJI encoded values are interpreted as the bytes of Shift-JIS
234     * encoded characters (note that this is the case even if an ECI specifies a different
235     * encoding).
236     */
237    #[cfg(feature = "allow_forced_iso_ied_18004_compliance")]
238    QrAssumeSpecConformInput(bool),
239
240    /**
241     * Translate the ASCII values parsed by the Telepen reader into the Telepen Numeric form; use {@link Boolean#TRUE}.
242     */
243    TelepenAsNumeric(bool),
244}
245
246#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
247#[derive(Default, Clone)]
248pub struct DecodeHints {
249    /**
250     * Unspecified, application-specific hint. Maps to an unspecified {@link Object}.
251     */
252    pub Other: Option<String>,
253
254    /**
255     * Image is a pure monochrome image of a barcode. Doesn't matter what it maps to;
256     * use {@link Boolean#TRUE}.
257     */
258    pub PureBarcode: Option<bool>,
259
260    /**
261     * Image is known to be of one of a few possible formats.
262     * Maps to a {@link List} of {@link BarcodeFormat}s.
263     */
264    pub PossibleFormats: Option<HashSet<BarcodeFormat>>,
265
266    /**
267     * Spend more time to try to find a barcode; optimize for accuracy, not speed.
268     * Doesn't matter what it maps to; use {@link Boolean#TRUE}.
269     */
270    pub TryHarder: Option<bool>,
271
272    /**
273     * Specifies what character encoding to use when decoding, where applicable (type String)
274     */
275    pub CharacterSet: Option<String>,
276
277    /**
278     * Allowed lengths of encoded data -- reject anything else. Maps to an {@code int[]}.
279     */
280    pub AllowedLengths: Option<Vec<u32>>,
281
282    /**
283     * Assume Code 39 codes employ a check digit. Doesn't matter what it maps to;
284     * use {@link Boolean#TRUE}.
285     */
286    pub AssumeCode39CheckDigit: Option<bool>,
287
288    /**
289     * Assume the barcode is being processed as a GS1 barcode, and modify behavior as needed.
290     * For example this affects FNC1 handling for Code 128 (aka GS1-128). Doesn't matter what it maps to;
291     * use {@link Boolean#TRUE}.
292     */
293    pub AssumeGs1: Option<bool>,
294
295    /**
296     * If true, return the start and end digits in a Codabar barcode instead of stripping them. They
297     * are alpha, whereas the rest are numeric. By default, they are stripped, but this causes them
298     * to not be. Doesn't matter what it maps to; use {@link Boolean#TRUE}.
299     */
300    pub ReturnCodabarStartEnd: Option<bool>,
301
302    /**
303     * The caller needs to be notified via callback when a possible {@link Point}
304     * is found. Maps to a {@link PointCallback}.
305     */
306    #[cfg_attr(feature = "serde", serde(skip_serializing, skip_deserializing))]
307    pub NeedResultPointCallback: Option<PointCallback>,
308
309    /**
310     * Allowed extension lengths for EAN or UPC barcodes. Other formats will ignore this.
311     * Maps to an {@code int[]} of the allowed extension lengths, for example [2], [5], or [2, 5].
312     * If it is optional to have an extension, do not set this hint. If this is set,
313     * and a UPC or EAN barcode is found but an extension is not, then no result will be returned
314     * at all.
315     */
316    pub AllowedEanExtensions: Option<Vec<u32>>,
317
318    /**
319     * If true, also tries to decode as inverted image. All configured decoders are simply called a
320     * second time with an inverted image. Doesn't matter what it maps to; use {@link Boolean#TRUE}.
321     */
322    pub AlsoInverted: Option<bool>,
323
324    /**
325     * Specifies that the codes are expected to be in conformance with the specification
326     * ISO/IEC 18004 regading the interpretation of character encoding. Values encoded in BYTE mode
327     * or in KANJI mode are interpreted as ISO-8859-1 characters unless an ECI specified at a prior
328     * location in the input specified a different encoding. By default the encoding of BYTE encoded
329     * values is determinied by the {@link #CHARACTER_SET} hint or otherwise by a heuristic that
330     * examines the bytes. By default KANJI encoded values are interpreted as the bytes of Shift-JIS
331     * encoded characters (note that this is the case even if an ECI specifies a different
332     * encoding).
333     */
334    #[cfg(feature = "allow_forced_iso_ied_18004_compliance")]
335    pub QrAssumeSpecConformInput: Option<bool>,
336
337    /**
338     * Translate the ASCII values parsed by the Telepen reader into the Telepen Numeric form; use {@link Boolean#TRUE}.
339     */
340    pub TelepenAsNumeric: Option<bool>,
341}
342
343impl From<super::DecodingHintDictionary> for DecodeHints {
344    fn from(value: super::DecodingHintDictionary) -> Self {
345        let mut new_self: Self = Self::default();
346        for (_, v) in value.into_iter() {
347            match v {
348                DecodeHintValue::Other(v) => new_self.Other = Some(v),
349                DecodeHintValue::PureBarcode(v) => new_self.PureBarcode = Some(v),
350                DecodeHintValue::PossibleFormats(v) => new_self.PossibleFormats = Some(v),
351                DecodeHintValue::TryHarder(v) => new_self.TryHarder = Some(v),
352                DecodeHintValue::CharacterSet(v) => new_self.CharacterSet = Some(v),
353                DecodeHintValue::AllowedLengths(v) => new_self.AllowedLengths = Some(v),
354                DecodeHintValue::AssumeCode39CheckDigit(v) => {
355                    new_self.AssumeCode39CheckDigit = Some(v)
356                }
357                DecodeHintValue::AssumeGs1(v) => new_self.AssumeGs1 = Some(v),
358                DecodeHintValue::ReturnCodabarStartEnd(v) => {
359                    new_self.ReturnCodabarStartEnd = Some(v)
360                }
361                DecodeHintValue::NeedResultPointCallback(v) => {
362                    new_self.NeedResultPointCallback = Some(v)
363                }
364                DecodeHintValue::AllowedEanExtensions(v) => new_self.AllowedEanExtensions = Some(v),
365                DecodeHintValue::AlsoInverted(v) => new_self.AlsoInverted = Some(v),
366                DecodeHintValue::TelepenAsNumeric(v) => new_self.TelepenAsNumeric = Some(v),
367                #[cfg(feature = "allow_forced_iso_ied_18004_compliance")]
368                DecodeHintValue::QrAssumeSpecConformInput(v) => {
369                    new_self.QrAssumeSpecConformInput = Some(v)
370                }
371            }
372        }
373        new_self
374    }
375}
376
377impl From<DecodeHints> for super::DecodingHintDictionary {
378    fn from(value: DecodeHints) -> Self {
379        let mut new_self = HashMap::default();
380
381        if let Some(v) = value.Other {
382            new_self.insert(DecodeHintType::OTHER, DecodeHintValue::Other(v));
383        }
384
385        if let Some(v) = value.PureBarcode {
386            new_self.insert(
387                DecodeHintType::PURE_BARCODE,
388                DecodeHintValue::PureBarcode(v),
389            );
390        }
391
392        if let Some(v) = value.PossibleFormats {
393            new_self.insert(
394                DecodeHintType::POSSIBLE_FORMATS,
395                DecodeHintValue::PossibleFormats(v),
396            );
397        }
398
399        if let Some(v) = value.TryHarder {
400            new_self.insert(DecodeHintType::TRY_HARDER, DecodeHintValue::TryHarder(v));
401        }
402
403        if let Some(v) = value.CharacterSet {
404            new_self.insert(
405                DecodeHintType::CHARACTER_SET,
406                DecodeHintValue::CharacterSet(v),
407            );
408        }
409
410        if let Some(v) = value.AllowedLengths {
411            new_self.insert(
412                DecodeHintType::ALLOWED_LENGTHS,
413                DecodeHintValue::AllowedLengths(v),
414            );
415        }
416
417        if let Some(v) = value.AssumeCode39CheckDigit {
418            new_self.insert(
419                DecodeHintType::ASSUME_CODE_39_CHECK_DIGIT,
420                DecodeHintValue::AssumeCode39CheckDigit(v),
421            );
422        }
423
424        if let Some(v) = value.AssumeGs1 {
425            new_self.insert(DecodeHintType::ASSUME_GS1, DecodeHintValue::AssumeGs1(v));
426        }
427
428        if let Some(v) = value.ReturnCodabarStartEnd {
429            new_self.insert(
430                DecodeHintType::RETURN_CODABAR_START_END,
431                DecodeHintValue::ReturnCodabarStartEnd(v),
432            );
433        }
434
435        if let Some(v) = value.NeedResultPointCallback {
436            new_self.insert(
437                DecodeHintType::NEED_RESULT_POINT_CALLBACK,
438                DecodeHintValue::NeedResultPointCallback(v),
439            );
440        }
441
442        if let Some(v) = value.AllowedEanExtensions {
443            new_self.insert(
444                DecodeHintType::ALLOWED_EAN_EXTENSIONS,
445                DecodeHintValue::AllowedEanExtensions(v),
446            );
447        }
448
449        if let Some(v) = value.AlsoInverted {
450            new_self.insert(
451                DecodeHintType::ALSO_INVERTED,
452                DecodeHintValue::AlsoInverted(v),
453            );
454        }
455
456        if let Some(v) = value.TelepenAsNumeric {
457            new_self.insert(
458                DecodeHintType::TELEPEN_AS_NUMERIC,
459                DecodeHintValue::TelepenAsNumeric(v),
460            );
461        }
462
463        #[cfg(feature = "allow_forced_iso_ied_18004_compliance")]
464        if let Some(v) = value.QrAssumeSpecConformInput {
465            new_self.insert(
466                DecodeHintType::QR_ASSUME_SPEC_CONFORM_INPUT,
467                DecodeHintValue::QrAssumeSpecConformInput(v),
468            );
469        }
470
471        new_self
472    }
473}
474
475impl DecodeHints {
476    pub fn with(mut self, value: DecodeHintValue) -> Self {
477        match value {
478            DecodeHintValue::Other(v) => self.Other = Some(v),
479            DecodeHintValue::PureBarcode(v) => self.PureBarcode = Some(v),
480            DecodeHintValue::PossibleFormats(v) => self.PossibleFormats = Some(v),
481            DecodeHintValue::TryHarder(v) => self.TryHarder = Some(v),
482            DecodeHintValue::CharacterSet(v) => self.CharacterSet = Some(v),
483            DecodeHintValue::AllowedLengths(v) => self.AllowedLengths = Some(v),
484            DecodeHintValue::AssumeCode39CheckDigit(v) => self.AssumeCode39CheckDigit = Some(v),
485            DecodeHintValue::AssumeGs1(v) => self.AssumeGs1 = Some(v),
486            DecodeHintValue::ReturnCodabarStartEnd(v) => self.ReturnCodabarStartEnd = Some(v),
487            DecodeHintValue::NeedResultPointCallback(v) => self.NeedResultPointCallback = Some(v),
488            DecodeHintValue::AllowedEanExtensions(v) => self.AllowedEanExtensions = Some(v),
489            DecodeHintValue::AlsoInverted(v) => self.AlsoInverted = Some(v),
490            DecodeHintValue::TelepenAsNumeric(v) => self.TelepenAsNumeric = Some(v),
491            #[cfg(feature = "allow_forced_iso_ied_18004_compliance")]
492            DecodeHintValue::QrAssumeSpecConformInput(v) => self.QrAssumeSpecConformInput = Some(v),
493        }
494        self
495    }
496}